Improve error handling when playing unloaded sounds

This commit is contained in:
Xavion3 2025-09-02 06:13:15 +10:00
parent 17c28c4024
commit bd7de61a56
7 changed files with 70 additions and 43 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;
config = config ?? {};
try {
@ -2354,16 +2354,19 @@ export class BattleScene extends SceneBase {
this.sound.play(key, config);
return this.sound.get(key) as AnySound;
} catch {
console.log(`${key} not found`);
return sound as AnySound;
console.warn(`${key} not found`);
return null;
}
}
playSoundWithoutBgm(soundName: string, pauseDuration?: number): AnySound {
playSoundWithoutBgm(soundName: string, pauseDuration?: number): AnySound | null {
this.bgmCache.add(soundName);
const resumeBgm = this.pauseBgm();
this.playSound(soundName);
const sound = this.sound.get(soundName) as AnySound;
const sound = this.sound.get(soundName);
if (!sound) {
return sound;
}
if (this.bgmResumeTimer) {
this.bgmResumeTimer.destroy();
}
@ -2373,7 +2376,7 @@ export class BattleScene extends SceneBase {
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. */

View File

@ -291,9 +291,17 @@ class AnimTimedSoundEvent extends AnimTimedEvent {
} catch (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((battleAnim.user!.cry(soundConfig).totalDuration * 1000) / 33.33); // TODO: is the bang behind user correct?
return Math.ceil((sound.totalDuration * 1000) / 33.33);
}
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 {

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);
let cry: AnySound | null = globalScene.sound.get(cryKey) as AnySound;
if (cry?.pendingRemove) {
cry = null;
}
cry = globalScene.playSound(cry ?? cryKey, soundConfig);
if (ignorePlay) {
if (cry && ignorePlay) {
cry.stop();
}
return cry;

View File

@ -4547,21 +4547,28 @@ 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 cry = this.getSpeciesForm(undefined, true).cry(soundConfig);
if (!cry) {
return cry;
}
let duration = cry.totalDuration * 1000;
if (this.fusionSpecies && this.getSpeciesForm(undefined, true) !== this.getFusionSpeciesForm(undefined, true)) {
let fusionCry = this.getFusionSpeciesForm(undefined, true).cry(soundConfig, true);
if (!fusionCry) {
return cry;
}
duration = Math.min(duration, fusionCry.totalDuration * 1000);
fusionCry.destroy();
scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => {
try {
SoundFade.fadeOut(scene, cry, fixedInt(Math.ceil(duration * 0.2)));
fusionCry = this.getFusionSpeciesForm(undefined, true).cry({
seek: Math.max(fusionCry.totalDuration * 0.4, 0),
seek: Math.max(fusionCry!.totalDuration * 0.4, 0),
...soundConfig,
});
if (fusionCry) {
SoundFade.fadeIn(
scene,
fusionCry,
@ -4569,6 +4576,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
scene.masterVolume * scene.fieldVolume,
0,
);
}
} catch (err) {
console.error(err);
}
@ -4596,14 +4604,14 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
crySoundConfig.rate = 0.7;
}
}
const cry = globalScene.playSound(key, crySoundConfig) as AnySound;
const cry = globalScene.playSound(key, crySoundConfig);
if (!cry || globalScene.fieldVolume === 0) {
callback();
return;
}
const sprite = this.getSprite();
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 frameThreshold: number;
@ -4656,20 +4664,20 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
const key = this.species.getCryKey(this.formIndex);
let i = 0;
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 tintSprite = this.getTintSprite();
let duration = cry.totalDuration * 1000;
const fusionCryKey = this.fusionSpecies!.getCryKey(this.fusionFormIndex);
let fusionCry = globalScene.playSound(fusionCryKey, {
rate: rate,
}) as AnySound;
});
if (!cry || !fusionCry || globalScene.fieldVolume === 0) {
callback();
return;
}
fusionCry.stop();
let duration = cry.totalDuration * 1000;
duration = Math.min(duration, fusionCry.totalDuration * 1000);
fusionCry.destroy();
const delay = Math.max(duration * 0.05, 25);
@ -4712,9 +4720,10 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
if (i === transitionIndex && fusionCryKey) {
SoundFade.fadeOut(globalScene, cry, fixedInt(Math.ceil((duration / rate) * 0.2)));
fusionCry = globalScene.playSound(fusionCryKey, {
seek: Math.max(fusionCry.totalDuration * 0.4, 0),
seek: Math.max(fusionCry!.totalDuration * 0.4, 0),
rate: rate,
});
if (fusionCry) {
SoundFade.fadeIn(
globalScene,
fusionCry,
@ -4723,6 +4732,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container {
0,
);
}
}
rate *= 0.99;
if (cry && !cry.pendingRemove) {
cry.setRate(rate);

View File

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

View File

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

View File

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