Merge pull request #6467 from Xavion3/sound-error-improvement

Sound error handling improvement
This commit is contained in:
Sirz Benjie 2025-09-01 17:24:33 -05:00 committed by GitHub
commit 9f19c6bea2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 73 additions and 44 deletions

View File

@ -2318,7 +2318,7 @@ export class BattleScene extends SceneBase {
}); });
} }
playSound(sound: string | AnySound, config?: object): AnySound { playSound(sound: string | AnySound, config?: object): AnySound | null {
const key = typeof sound === "string" ? sound : sound.key; const key = typeof sound === "string" ? sound : sound.key;
config = config ?? {}; config = config ?? {};
try { try {
@ -2354,16 +2354,19 @@ export class BattleScene extends SceneBase {
this.sound.play(key, config); this.sound.play(key, config);
return this.sound.get(key) as AnySound; return this.sound.get(key) as AnySound;
} catch { } catch {
console.log(`${key} not found`); console.warn(`${key} not found`);
return sound as AnySound; return null;
} }
} }
playSoundWithoutBgm(soundName: string, pauseDuration?: number): AnySound { playSoundWithoutBgm(soundName: string, pauseDuration?: number): AnySound | null {
this.bgmCache.add(soundName); this.bgmCache.add(soundName);
const resumeBgm = this.pauseBgm(); const resumeBgm = this.pauseBgm();
this.playSound(soundName); this.playSound(soundName);
const sound = this.sound.get(soundName) as AnySound; const sound = this.sound.get(soundName);
if (!sound) {
return sound;
}
if (this.bgmResumeTimer) { if (this.bgmResumeTimer) {
this.bgmResumeTimer.destroy(); this.bgmResumeTimer.destroy();
} }
@ -2373,7 +2376,7 @@ export class BattleScene extends SceneBase {
this.bgmResumeTimer = null; this.bgmResumeTimer = null;
}); });
} }
return sound; return sound as AnySound;
} }
/** The loop point of any given battle, mystery encounter, or title track, read as seconds and milliseconds. */ /** The loop point of any given battle, mystery encounter, or title track, read as seconds and milliseconds. */

View File

@ -291,9 +291,17 @@ class AnimTimedSoundEvent extends AnimTimedEvent {
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
return Math.ceil((globalScene.sound.get(`battle_anims/${this.resourceName}`).totalDuration * 1000) / 33.33); const sound = globalScene.sound.get(`battle_anims/${this.resourceName}`);
if (!sound) {
return 0;
}
return Math.ceil((sound.totalDuration * 1000) / 33.33);
} }
return Math.ceil((battleAnim.user!.cry(soundConfig).totalDuration * 1000) / 33.33); // TODO: is the bang behind user correct? const cry = battleAnim.user!.cry(soundConfig); // TODO: is the bang behind user correct?
if (!cry) {
return 0;
}
return Math.ceil((cry.totalDuration * 1000) / 33.33);
} }
getEventType(): string { getEventType(): string {

View File

@ -593,14 +593,14 @@ export abstract class PokemonSpeciesForm {
}); });
} }
cry(soundConfig?: Phaser.Types.Sound.SoundConfig, ignorePlay?: boolean): AnySound { cry(soundConfig?: Phaser.Types.Sound.SoundConfig, ignorePlay?: boolean): AnySound | null {
const cryKey = this.getCryKey(this.formIndex); const cryKey = this.getCryKey(this.formIndex);
let cry: AnySound | null = globalScene.sound.get(cryKey) as AnySound; let cry: AnySound | null = globalScene.sound.get(cryKey) as AnySound;
if (cry?.pendingRemove) { if (cry?.pendingRemove) {
cry = null; cry = null;
} }
cry = globalScene.playSound(cry ?? cryKey, soundConfig); cry = globalScene.playSound(cry ?? cryKey, soundConfig);
if (ignorePlay) { if (cry && ignorePlay) {
cry.stop(); cry.stop();
} }
return cry; return cry;

View File

@ -4547,28 +4547,36 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
}); });
} }
cry(soundConfig?: Phaser.Types.Sound.SoundConfig, sceneOverride?: BattleScene): AnySound { cry(soundConfig?: Phaser.Types.Sound.SoundConfig, sceneOverride?: BattleScene): AnySound | null {
const scene = sceneOverride ?? globalScene; // TODO: is `sceneOverride` needed? const scene = sceneOverride ?? globalScene; // TODO: is `sceneOverride` needed?
const cry = this.getSpeciesForm(undefined, true).cry(soundConfig); const cry = this.getSpeciesForm(undefined, true).cry(soundConfig);
if (!cry) {
return cry;
}
let duration = cry.totalDuration * 1000; let duration = cry.totalDuration * 1000;
if (this.fusionSpecies && this.getSpeciesForm(undefined, true) !== this.getFusionSpeciesForm(undefined, true)) { if (this.fusionSpecies && this.getSpeciesForm(undefined, true) !== this.getFusionSpeciesForm(undefined, true)) {
let fusionCry = this.getFusionSpeciesForm(undefined, true).cry(soundConfig, true); const fusionCry = this.getFusionSpeciesForm(undefined, true).cry(soundConfig, true);
if (!fusionCry) {
return cry;
}
duration = Math.min(duration, fusionCry.totalDuration * 1000); duration = Math.min(duration, fusionCry.totalDuration * 1000);
fusionCry.destroy(); fusionCry.destroy();
scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => { scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => {
try { try {
SoundFade.fadeOut(scene, cry, fixedInt(Math.ceil(duration * 0.2))); SoundFade.fadeOut(scene, cry, fixedInt(Math.ceil(duration * 0.2)));
fusionCry = this.getFusionSpeciesForm(undefined, true).cry({ const fusionCryInner = this.getFusionSpeciesForm(undefined, true).cry({
seek: Math.max(fusionCry.totalDuration * 0.4, 0), seek: Math.max(fusionCry.totalDuration * 0.4, 0),
...soundConfig, ...soundConfig,
}); });
SoundFade.fadeIn( if (fusionCryInner) {
scene, SoundFade.fadeIn(
fusionCry, scene,
fixedInt(Math.ceil(duration * 0.2)), fusionCryInner,
scene.masterVolume * scene.fieldVolume, fixedInt(Math.ceil(duration * 0.2)),
0, scene.masterVolume * scene.fieldVolume,
); 0,
);
}
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
@ -4596,14 +4604,14 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
crySoundConfig.rate = 0.7; crySoundConfig.rate = 0.7;
} }
} }
const cry = globalScene.playSound(key, crySoundConfig) as AnySound; const cry = globalScene.playSound(key, crySoundConfig);
if (!cry || globalScene.fieldVolume === 0) { if (!cry || globalScene.fieldVolume === 0) {
callback(); callback();
return; return;
} }
const sprite = this.getSprite(); const sprite = this.getSprite();
const tintSprite = this.getTintSprite(); const tintSprite = this.getTintSprite();
const delay = Math.max(globalScene.sound.get(key).totalDuration * 50, 25); const delay = Math.max(cry.totalDuration * 50, 25);
let frameProgress = 0; let frameProgress = 0;
let frameThreshold: number; let frameThreshold: number;
@ -4656,20 +4664,20 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const key = this.species.getCryKey(this.formIndex); const key = this.species.getCryKey(this.formIndex);
let i = 0; let i = 0;
let rate = 0.85; let rate = 0.85;
const cry = globalScene.playSound(key, { rate: rate }) as AnySound; const cry = globalScene.playSound(key, { rate: rate });
const sprite = this.getSprite(); const sprite = this.getSprite();
const tintSprite = this.getTintSprite(); const tintSprite = this.getTintSprite();
let duration = cry.totalDuration * 1000;
const fusionCryKey = this.fusionSpecies!.getCryKey(this.fusionFormIndex); const fusionCryKey = this.fusionSpecies!.getCryKey(this.fusionFormIndex);
let fusionCry = globalScene.playSound(fusionCryKey, { let fusionCry = globalScene.playSound(fusionCryKey, {
rate: rate, rate: rate,
}) as AnySound; });
if (!cry || !fusionCry || globalScene.fieldVolume === 0) { if (!cry || !fusionCry || globalScene.fieldVolume === 0) {
callback(); callback();
return; return;
} }
fusionCry.stop(); fusionCry.stop();
let duration = cry.totalDuration * 1000;
duration = Math.min(duration, fusionCry.totalDuration * 1000); duration = Math.min(duration, fusionCry.totalDuration * 1000);
fusionCry.destroy(); fusionCry.destroy();
const delay = Math.max(duration * 0.05, 25); const delay = Math.max(duration * 0.05, 25);
@ -4712,16 +4720,20 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
if (i === transitionIndex && fusionCryKey) { if (i === transitionIndex && fusionCryKey) {
SoundFade.fadeOut(globalScene, cry, fixedInt(Math.ceil((duration / rate) * 0.2))); SoundFade.fadeOut(globalScene, cry, fixedInt(Math.ceil((duration / rate) * 0.2)));
fusionCry = globalScene.playSound(fusionCryKey, { fusionCry = globalScene.playSound(fusionCryKey, {
seek: Math.max(fusionCry.totalDuration * 0.4, 0), // TODO: This bang is correct as this callback can only be called once, but
// this whole block with conditionally reassigning fusionCry needs a second lock.
seek: Math.max(fusionCry!.totalDuration * 0.4, 0),
rate: rate, rate: rate,
}); });
SoundFade.fadeIn( if (fusionCry) {
globalScene, SoundFade.fadeIn(
fusionCry, globalScene,
fixedInt(Math.ceil((duration / rate) * 0.2)), fusionCry,
globalScene.masterVolume * globalScene.fieldVolume, fixedInt(Math.ceil((duration / rate) * 0.2)),
0, globalScene.masterVolume * globalScene.fieldVolume,
); 0,
);
}
} }
rate *= 0.99; rate *= 0.99;
if (cry && !cry.pendingRemove) { if (cry && !cry.pendingRemove) {

View File

@ -64,7 +64,7 @@ export class EggHatchPhase extends Phase {
private canSkip: boolean; private canSkip: boolean;
private skipped: boolean; private skipped: boolean;
/** The sound effect being played when the egg is hatched */ /** The sound effect being played when the egg is hatched */
private evolutionBgm: AnySound; private evolutionBgm: AnySound | null;
private eggLapsePhase: EggLapsePhase; private eggLapsePhase: EggLapsePhase;
constructor(hatchScene: EggLapsePhase, egg: Egg, eggsToHatchCount: number) { constructor(hatchScene: EggLapsePhase, egg: Egg, eggsToHatchCount: number) {

View File

@ -28,7 +28,7 @@ export class EvolutionPhase extends Phase {
private evolution: SpeciesFormEvolution | null; private evolution: SpeciesFormEvolution | null;
private fusionSpeciesEvolved: boolean; // Whether the evolution is of the fused species private fusionSpeciesEvolved: boolean; // Whether the evolution is of the fused species
private evolutionBgm: AnySound; private evolutionBgm: AnySound | null;
private evolutionHandler: EvolutionSceneHandler; private evolutionHandler: EvolutionSceneHandler;
/** Container for all assets used by the scene. When the scene is cleared, the children within this are destroyed. */ /** Container for all assets used by the scene. When the scene is cleared, the children within this are destroyed. */
@ -298,7 +298,9 @@ export class EvolutionPhase extends Phase {
this.evolutionBg.setVisible(false); this.evolutionBg.setVisible(false);
}, },
}); });
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100); if (this.evolutionBgm) {
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
}
} }
/** /**
@ -378,7 +380,9 @@ export class EvolutionPhase extends Phase {
* Fadeout evolution music, play the cry, show the evolution completed text, and end the phase * Fadeout evolution music, play the cry, show the evolution completed text, and end the phase
*/ */
private onEvolutionComplete(evolvedPokemon: Pokemon) { private onEvolutionComplete(evolvedPokemon: Pokemon) {
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100); if (this.evolutionBgm) {
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
}
globalScene.time.delayedCall(250, () => { globalScene.time.delayedCall(250, () => {
this.pokemon.cry(); this.pokemon.cry();
globalScene.time.delayedCall(1250, () => { globalScene.time.delayedCall(1250, () => {

View File

@ -38,13 +38,15 @@ export class PartyHealPhase extends BattlePhase {
pokemon.updateInfo(true); pokemon.updateInfo(true);
} }
const healSong = globalScene.playSoundWithoutBgm("heal"); const healSong = globalScene.playSoundWithoutBgm("heal");
globalScene.time.delayedCall(fixedInt(healSong.totalDuration * 1000), () => { if (healSong) {
healSong.destroy(); globalScene.time.delayedCall(fixedInt(healSong.totalDuration * 1000), () => {
if (this.resumeBgm && bgmPlaying) { healSong.destroy();
globalScene.playBgm(); if (this.resumeBgm && bgmPlaying) {
} globalScene.playBgm();
globalScene.ui.fadeIn(500).then(() => this.end()); }
}); globalScene.ui.fadeIn(500).then(() => this.end());
});
}
}); });
globalScene.arena.playerTerasUsed = 0; globalScene.arena.playerTerasUsed = 0;
} }