hedgewars/uSound.pas
changeset 14042 bf8b7c166b3c
parent 14041 bf14c7c1be02
child 14046 44f20c9e6861
--- a/hedgewars/uSound.pas	Sun Oct 28 14:08:13 2018 +0100
+++ b/hedgewars/uSound.pas	Tue Oct 30 23:08:43 2018 +0100
@@ -62,14 +62,15 @@
 // Plays the sound snd [from a given voicepack],
 // if keepPlaying is given and true,
 // then the sound's playback won't be interrupted if asked to play again.
-procedure PlaySound(snd: TSound);
-procedure PlaySound(snd: TSound; keepPlaying: boolean);
-procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean);
-procedure PlaySound(snd: TSound; keepPlaying, ignoreMask, soundAsMusic: boolean);
-procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
-procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
-procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask: boolean);
-procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask, soundAsMusic: boolean);
+// Returns true if sound was found and is played, false otherwise.
+function PlaySound(snd: TSound): boolean;
+function PlaySound(snd: TSound; keepPlaying: boolean): boolean;
+function PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean): boolean;
+function PlaySound(snd: TSound; keepPlaying, ignoreMask, soundAsMusic: boolean): boolean;
+function PlaySoundV(snd: TSound; voicepack: PVoicepack): boolean;
+function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean): boolean;
+function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask: boolean): boolean;
+function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask, soundAsMusic: boolean): boolean;
 
 // Plays/stops a sound to replace the main background music temporarily.
 procedure PlayMusicSound(snd: TSound);
@@ -89,8 +90,11 @@
 procedure StopSoundChan(chn: LongInt);
 procedure StopSoundChan(chn, fadems: LongInt);
 
+// Add voice to the voice queue
 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
-procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean);
+procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask, isFallback: boolean);
+
+// Actually play next voice
 procedure PlayNextVoice;
 
 
@@ -125,6 +129,7 @@
 
 var Volume: LongInt;
     SoundTimerTicks: Longword;
+    LastVoiceFailed: boolean;
 implementation
 uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer;
 
@@ -140,14 +145,14 @@
     isAutoDampening: boolean;
     isSEBackup: boolean;
     VoiceList : array[0..7] of TVoice =  (
-                    ( snd: sndNone; voicepack: nil),
-                    ( snd: sndNone; voicepack: nil),
-                    ( snd: sndNone; voicepack: nil),
-                    ( snd: sndNone; voicepack: nil),
-                    ( snd: sndNone; voicepack: nil),
-                    ( snd: sndNone; voicepack: nil),
-                    ( snd: sndNone; voicepack: nil),
-                    ( snd: sndNone; voicepack: nil));
+                    ( snd: sndNone; voicepack: nil; isFallback: false),
+                    ( snd: sndNone; voicepack: nil; isFallback: false),
+                    ( snd: sndNone; voicepack: nil; isFallback: false),
+                    ( snd: sndNone; voicepack: nil; isFallback: false),
+                    ( snd: sndNone; voicepack: nil; isFallback: false),
+                    ( snd: sndNone; voicepack: nil; isFallback: false),
+                    ( snd: sndNone; voicepack: nil; isFallback: false),
+                    ( snd: sndNone; voicepack: nil; isFallback: false));
     Soundz: array[TSound] of record
             FileName: string[31];
             Path, AltPath    : TPathType;
@@ -499,45 +504,47 @@
         GetFallbackV := sndNone;
 end;
 
-procedure PlaySound(snd: TSound);
+function PlaySound(snd: TSound): boolean;
 begin
-    PlaySoundV(snd, nil, false, false, false);
+    PlaySound:= PlaySoundV(snd, nil, false, false, false);
 end;
 
-procedure PlaySound(snd: TSound; keepPlaying: boolean);
+function PlaySound(snd: TSound; keepPlaying: boolean): boolean;
 begin
-    PlaySoundV(snd, nil, keepPlaying, false, false);
+    PlaySound:= PlaySoundV(snd, nil, keepPlaying, false, false);
 end;
 
-procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean);
+function PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean): boolean;
 begin
-    PlaySoundV(snd, nil, keepPlaying, ignoreMask, false);
+    PlaySound:= PlaySoundV(snd, nil, keepPlaying, ignoreMask, false);
 end;
 
-procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask, soundAsMusic: boolean);
+function PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask, soundAsMusic: boolean): boolean;
 begin
-    PlaySoundV(snd, nil, keepPlaying, ignoreMask, soundAsMusic);
+    PlaySound:= PlaySoundV(snd, nil, keepPlaying, ignoreMask, soundAsMusic);
 end;
 
-procedure PlaySoundV(snd: TSound; voicepack: PVoicepack);
+function PlaySoundV(snd: TSound; voicepack: PVoicepack): boolean;
 begin
-    PlaySoundV(snd, voicepack, false, false, false);
+    PlaySoundV:= PlaySoundV(snd, voicepack, false, false, false);
 end;
 
-procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
+function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean): boolean;
 begin
-    PlaySoundV(snd, voicepack, keepPlaying, false, false);
+    PlaySoundV:= PlaySoundV(snd, voicepack, keepPlaying, false, false);
 end;
 
-procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask: boolean);
+function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask: boolean): boolean;
 begin
-    PlaySoundV(snd, voicepack, keepPlaying, ignoreMask, false);
+    PlaySoundV:= PlaySoundV(snd, voicepack, keepPlaying, ignoreMask, false);
 end;
 
-procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask, soundAsMusic: boolean);
+function PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying, ignoreMask, soundAsMusic: boolean): boolean;
 var s:shortstring;
 rwops: PSDL_RWops;
 begin
+    s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName;
+    PlaySoundV:= false;
     if ((not isSoundEnabled) and (not (soundAsMusic and isMusicEnabled))) or fastUntilLag then
         exit;
 
@@ -576,7 +583,8 @@
             else
                 WriteLnToConsole(msgOK)
             end;
-        lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], 0, -1)
+        lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], 0, -1);
+        PlaySoundV:= true;
         end
     else
         begin
@@ -597,7 +605,8 @@
             if SDLCheck(defVoicepack^.chunks[snd] <> nil, 'Mix_LoadWAV_RW', true) then exit;
             WriteLnToConsole(msgOK);
             end;
-        lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1)
+        lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1);
+        PlaySoundV:= true;
         end;
 end;
 
@@ -615,10 +624,23 @@
 
 procedure AddVoice(snd: TSound; voicepack: PVoicepack);
 begin
-    AddVoice(snd, voicepack, false);
+    AddVoice(snd, voicepack, false, false);
 end;
 
-procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean);
+{
+AddVoice: Add a voice to the voice queue.
+* snd: Sound ID
+* voicepack: Hedgehog voicepack
+* ignoreMask: If true, the sound will be played anyway if masked by Lua
+* isFallback: If true, this sound is added as fallback if the sound previously added to the
+             queue was not found. Useful to make sure a voice is always played, even if
+             a voicepack is incomplete.
+             Example:
+                 AddVoice(sndRevenge, voiceAttacker);
+                 AddVoice(sndRegret, voiceVictim, false, true);
+             --> plays sndRegret if sndRevenge could not be played.
+}
+procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask, isFallback: boolean);
 var i : LongInt;
 begin
 
@@ -646,11 +668,13 @@
         begin
         VoiceList[i].snd:= snd;
         VoiceList[i].voicepack:= voicepack;
+        VoiceList[i].isFallback:= isFallback;
         end
 end;
 
 procedure PlayNextVoice;
 var i : LongInt;
+    played : boolean;
 begin
     if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd <> sndNone) and (lastChan[LastVoice.snd] <> -1) and (Mix_Playing(lastChan[LastVoice.snd]) <> 0)) then
         exit;
@@ -658,14 +682,19 @@
     while (i<High(VoiceList)) and (VoiceList[i].snd = sndNone) do
         inc(i);
 
-    if (VoiceList[i].snd <> sndNone) then
+    played:= false;
+    if (VoiceList[i].snd <> sndNone) and ((not VoiceList[i].isFallback) or LastVoiceFailed) then
         begin
         LastVoice.snd:= VoiceList[i].snd;
         LastVoice.voicepack:= VoiceList[i].voicepack;
+        LastVoice.isFallback:= VoiceList[i].isFallback;
         VoiceList[i].snd:= sndNone;
-        PlaySoundV(LastVoice.snd, LastVoice.voicepack)
+        played:= PlaySoundV(LastVoice.snd, LastVoice.voicepack);
+        // Remember if sound was not played.
+        LastVoiceFailed:= (not played);
         end
-    else LastVoice.snd:= sndNone;
+    else
+        LastVoice.snd:= sndNone;
 end;
 
 function LoopSound(snd: TSound): LongInt;
@@ -965,6 +994,7 @@
     Volume:= 0;
     SoundTimerTicks:= 0;
     defVoicepack:= AskForVoicepack('Default');
+    LastVoiceFailed:= false;
 
     for i:= Low(TSound) to High(TSound) do
         lastChan[i]:= -1;