61 // Plays the sound snd [from a given voicepack], |
61 // Plays the sound snd [from a given voicepack], |
62 // if keepPlaying is given and true, |
62 // if keepPlaying is given and true, |
63 // then the sound's playback won't be interrupted if asked to play again. |
63 // then the sound's playback won't be interrupted if asked to play again. |
64 procedure PlaySound(snd: TSound); |
64 procedure PlaySound(snd: TSound); |
65 procedure PlaySound(snd: TSound; keepPlaying: boolean); |
65 procedure PlaySound(snd: TSound; keepPlaying: boolean); |
|
66 procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean); |
66 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack); |
67 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack); |
67 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean); |
68 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean); |
|
69 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean; ignoreMask: boolean); |
68 |
70 |
69 // Plays sound snd [of voicepack] in a loop, but starts with fadems milliseconds of fade-in. |
71 // Plays sound snd [of voicepack] in a loop, but starts with fadems milliseconds of fade-in. |
70 // Returns sound channel of the looped sound. |
72 // Returns sound channel of the looped sound. |
71 function LoopSound(snd: TSound): LongInt; |
73 function LoopSound(snd: TSound): LongInt; |
72 function LoopSound(snd: TSound; fadems: LongInt): LongInt; |
74 function LoopSound(snd: TSound; fadems: LongInt): LongInt; |
78 procedure StopSound(snd: TSound); |
80 procedure StopSound(snd: TSound); |
79 procedure StopSoundChan(chn: LongInt); |
81 procedure StopSoundChan(chn: LongInt); |
80 procedure StopSoundChan(chn, fadems: LongInt); |
82 procedure StopSoundChan(chn, fadems: LongInt); |
81 |
83 |
82 procedure AddVoice(snd: TSound; voicepack: PVoicepack); |
84 procedure AddVoice(snd: TSound; voicepack: PVoicepack); |
|
85 procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean); |
83 procedure PlayNextVoice; |
86 procedure PlayNextVoice; |
84 |
87 |
85 |
88 |
86 // GLOBAL FUNCTIONS |
89 // GLOBAL FUNCTIONS |
87 |
90 |
99 procedure SetVolume(vol: LongInt); |
102 procedure SetVolume(vol: LongInt); |
100 |
103 |
101 // Modifies the sound volume of the game by voldelta and returns the new volume level. |
104 // Modifies the sound volume of the game by voldelta and returns the new volume level. |
102 function ChangeVolume(voldelta: LongInt): LongInt; |
105 function ChangeVolume(voldelta: LongInt): LongInt; |
103 |
106 |
|
107 // Returns the current volume in percent |
|
108 function GetVolumePercent(): LongInt; |
|
109 |
104 // Returns a pointer to the voicepack with the given name. |
110 // Returns a pointer to the voicepack with the given name. |
105 function AskForVoicepack(name: shortstring): Pointer; |
111 function AskForVoicepack(name: shortstring): Pointer; |
106 |
112 |
107 var MusicFN: shortstring; // music file name |
113 var MusicFN: shortstring; // music file name |
108 SDMusicFN: shortstring; // SD music file name |
114 SDMusicFN: shortstring; // SD music file name |
|
115 FallbackMusicFN: shortstring; // fallback music file name |
|
116 FallbackSDMusicFN: shortstring; // fallback SD music fille name |
109 |
117 |
110 var Volume: LongInt; |
118 var Volume: LongInt; |
111 SoundTimerTicks: Longword; |
119 SoundTimerTicks: Longword; |
112 implementation |
120 implementation |
113 uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer; |
121 uses uVariables, uConsole, uCommands, uDebug, uPhysFSLayer; |
176 (FileName: 'cake2.ogg'; Path: ptSounds; AltPath: ptNone),// sndCake |
184 (FileName: 'cake2.ogg'; Path: ptSounds; AltPath: ptNone),// sndCake |
177 (FileName: 'Ow1.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw1 |
185 (FileName: 'Ow1.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw1 |
178 (FileName: 'Ow2.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw2 |
186 (FileName: 'Ow2.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw2 |
179 (FileName: 'Ow3.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw3 |
187 (FileName: 'Ow3.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw3 |
180 (FileName: 'Ow4.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw4 |
188 (FileName: 'Ow4.ogg'; Path: ptVoices; AltPath: ptNone),// sndOw4 |
181 (FileName: 'Firepunch1.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch1 |
189 (FileName: 'Firepunch1.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch1 |
182 (FileName: 'Firepunch2.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch2 |
190 (FileName: 'Firepunch2.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch2 |
183 (FileName: 'Firepunch3.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch3 |
191 (FileName: 'Firepunch3.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch3 |
184 (FileName: 'Firepunch4.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch4 |
192 (FileName: 'Firepunch4.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch4 |
185 (FileName: 'Firepunch5.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch5 |
193 (FileName: 'Firepunch5.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch5 |
186 (FileName: 'Firepunch6.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirepunch6 |
194 (FileName: 'Firepunch6.ogg'; Path: ptVoices; AltPath: ptNone),// sndFirePunch6 |
187 (FileName: 'Melon.ogg'; Path: ptVoices; AltPath: ptNone),// sndMelon |
195 (FileName: 'Melon.ogg'; Path: ptVoices; AltPath: ptNone),// sndMelon |
188 (FileName: 'Hellish.ogg'; Path: ptSounds; AltPath: ptNone),// sndHellish |
196 (FileName: 'Hellish.ogg'; Path: ptSounds; AltPath: ptNone),// sndHellish |
189 (FileName: 'Yoohoo.ogg'; Path: ptSounds; AltPath: ptNone),// sndYoohoo |
197 (FileName: 'Yoohoo.ogg'; Path: ptSounds; AltPath: ptNone),// sndYoohoo |
190 (FileName: 'rcplane.ogg'; Path: ptSounds; AltPath: ptNone),// sndRCPlane |
198 (FileName: 'rcplane.ogg'; Path: ptSounds; AltPath: ptNone),// sndRCPlane |
191 (FileName: 'whipcrack.ogg'; Path: ptSounds; AltPath: ptNone),// sndWhipCrack |
199 (FileName: 'whipcrack.ogg'; Path: ptSounds; AltPath: ptNone),// sndWhipCrack |
276 (FileName: 'custom3.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom3 |
284 (FileName: 'custom3.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom3 |
277 (FileName: 'custom4.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom4 |
285 (FileName: 'custom4.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom4 |
278 (FileName: 'custom5.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom5 |
286 (FileName: 'custom5.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom5 |
279 (FileName: 'custom6.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom6 |
287 (FileName: 'custom6.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom6 |
280 (FileName: 'custom7.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom7 |
288 (FileName: 'custom7.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom7 |
281 (FileName: 'custom8.ogg'; Path: ptSounds; AltPath: ptNone) // sndCustom8 |
289 (FileName: 'custom8.ogg'; Path: ptSounds; AltPath: ptNone),// sndCustom8 |
|
290 (FileName: 'minigun.ogg'; Path: ptSounds; AltPath: ptNone) // sndMinigun |
282 ); |
291 ); |
283 |
292 |
284 |
293 |
285 function AskForVoicepack(name: shortstring): Pointer; |
294 function AskForVoicepack(name: shortstring): Pointer; |
286 var i: Longword; |
295 var i: Longword; |
407 end; |
416 end; |
408 end; |
417 end; |
409 |
418 |
410 procedure PlaySound(snd: TSound); |
419 procedure PlaySound(snd: TSound); |
411 begin |
420 begin |
412 PlaySoundV(snd, nil, false); |
421 PlaySoundV(snd, nil, false, false); |
413 end; |
422 end; |
414 |
423 |
415 procedure PlaySound(snd: TSound; keepPlaying: boolean); |
424 procedure PlaySound(snd: TSound; keepPlaying: boolean); |
416 begin |
425 begin |
417 PlaySoundV(snd, nil, keepPlaying); |
426 PlaySoundV(snd, nil, keepPlaying, false); |
|
427 end; |
|
428 |
|
429 procedure PlaySound(snd: TSound; keepPlaying: boolean; ignoreMask: boolean); |
|
430 begin |
|
431 PlaySoundV(snd, nil, keepPlaying, ignoreMask); |
418 end; |
432 end; |
419 |
433 |
420 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack); |
434 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack); |
421 begin |
435 begin |
422 PlaySoundV(snd, voicepack, false); |
436 PlaySoundV(snd, voicepack, false, false); |
423 end; |
437 end; |
424 |
438 |
425 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean); |
439 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean); |
|
440 begin |
|
441 PlaySoundV(snd, voicepack, keepPlaying, false); |
|
442 end; |
|
443 |
|
444 procedure PlaySoundV(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean; ignoreMask: boolean); |
426 var s:shortstring; |
445 var s:shortstring; |
427 rwops: PSDL_RWops; |
446 rwops: PSDL_RWops; |
428 begin |
447 begin |
429 if (not isSoundEnabled) or fastUntilLag then |
448 if (not isSoundEnabled) or fastUntilLag then |
430 exit; |
449 exit; |
431 |
450 |
432 if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then |
451 if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then |
|
452 exit; |
|
453 |
|
454 if (ignoreMask = false) and (MaskedSounds[snd] = true) then |
433 exit; |
455 exit; |
434 |
456 |
435 if (voicepack <> nil) then |
457 if (voicepack <> nil) then |
436 begin |
458 begin |
437 if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then |
459 if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then |
438 begin |
460 begin |
439 s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; |
461 s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; |
440 if (not pfsExists(s)) and (snd in [sndFirePunch2, sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6]) then |
462 // Fallback to sndFirePunch1 / sndOw1 / sndOoff1 if a “higher-numbered” sound is missing |
441 s:= cPathz[Soundz[sndFirePunch1].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; |
463 if (not pfsExists(s)) then |
|
464 begin |
|
465 if (snd in [sndFirePunch2, sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6]) then |
|
466 snd := sndFirePunch1 |
|
467 else if (snd in [sndOw2, sndOw3, sndOw4]) then |
|
468 snd := sndOw1 |
|
469 else if (snd in [sndOoff2, sndOoff3]) then |
|
470 snd := sndOoff1; |
|
471 s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; |
|
472 end; |
442 WriteToConsole(msgLoading + s + ' '); |
473 WriteToConsole(msgLoading + s + ' '); |
443 rwops := rwopsOpenRead(s); |
474 rwops := rwopsOpenRead(s); |
444 |
475 |
445 if rwops = nil then |
476 if rwops = nil then |
446 begin |
477 begin |
479 lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1) |
510 lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1) |
480 end; |
511 end; |
481 end; |
512 end; |
482 |
513 |
483 procedure AddVoice(snd: TSound; voicepack: PVoicepack); |
514 procedure AddVoice(snd: TSound; voicepack: PVoicepack); |
|
515 begin |
|
516 AddVoice(snd, voicepack, false); |
|
517 end; |
|
518 |
|
519 procedure AddVoice(snd: TSound; voicepack: PVoicepack; ignoreMask: boolean); |
484 var i : LongInt; |
520 var i : LongInt; |
485 begin |
521 begin |
|
522 |
486 if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd = snd) and (LastVoice.voicepack = voicepack)) then |
523 if (not isSoundEnabled) or fastUntilLag or ((LastVoice.snd = snd) and (LastVoice.voicepack = voicepack)) then |
487 exit; |
524 exit; |
|
525 if (ignoreMask = false) and (MaskedSounds[snd] = true) then |
|
526 exit; |
|
527 |
488 if (snd = sndVictory) or (snd = sndFlawless) then |
528 if (snd = sndVictory) or (snd = sndFlawless) then |
489 begin |
529 begin |
490 Mix_FadeOutChannel(-1, 800); |
530 Mix_FadeOutChannel(-1, 800); |
491 for i:= 0 to High(VoiceList) do |
531 for i:= 0 to High(VoiceList) do |
492 VoiceList[i].snd:= sndNone; |
532 VoiceList[i].snd:= sndNone; |
630 if SuddenDeath and (SDMusicFN <> '') then |
670 if SuddenDeath and (SDMusicFN <> '') then |
631 s:= '/Music/' + SDMusicFN |
671 s:= '/Music/' + SDMusicFN |
632 else s:= '/Music/' + MusicFN; |
672 else s:= '/Music/' + MusicFN; |
633 WriteToConsole(msgLoading + s + ' '); |
673 WriteToConsole(msgLoading + s + ' '); |
634 |
674 |
|
675 // Load normal music |
635 Mus:= Mix_LoadMUS_RW(rwopsOpenRead(s)); |
676 Mus:= Mix_LoadMUS_RW(rwopsOpenRead(s)); |
636 SDLCheck(Mus <> nil, 'Mix_LoadMUS_RW', false); |
677 SDLCheck(Mus <> nil, 'Mix_LoadMUS_RW', false); |
637 WriteLnToConsole(msgOK); |
678 if Mus <> nil then |
|
679 WriteLnToConsole(msgOK); |
|
680 |
|
681 // If normal music failed, try to get fallback music |
|
682 if Mus = nil then |
|
683 begin |
|
684 WriteLnToConsole('Music not found. Trying fallback music.'); |
|
685 if SuddenDeath and (FallbackSDMusicFN <> '') then |
|
686 s:= '/Music/' + FallbackSDMusicFN |
|
687 else if (not SuddenDeath) and (FallbackMusicFN <> '') then |
|
688 s:= '/Music/' + FallbackMusicFN |
|
689 else |
|
690 begin |
|
691 WriteLnToConsole('No fallback music configured!'); |
|
692 s:= '' |
|
693 end; |
|
694 |
|
695 if (s <> '') then |
|
696 begin |
|
697 WriteLnToConsole(msgLoading + s + ' '); |
|
698 Mus:= Mix_LoadMUS_RW(rwopsOpenRead(s)); |
|
699 SDLCheck(Mus <> nil, 'Mix_LoadMUS_RW', false); |
|
700 if Mus <> nil then |
|
701 WriteLnToConsole(msgOK) |
|
702 end; |
|
703 end; |
638 |
704 |
639 SDLCheck(Mix_FadeInMusic(Mus, -1, 3000) <> -1, 'Mix_FadeInMusic', false) |
705 SDLCheck(Mix_FadeInMusic(Mus, -1, 3000) <> -1, 'Mix_FadeInMusic', false) |
640 end; |
706 end; |
641 |
707 |
642 procedure SetVolume(vol: LongInt); |
708 procedure SetVolume(vol: LongInt); |
643 begin |
709 begin |
644 cInitVolume:= vol; |
710 cInitVolume:= vol; |
|
711 end; |
|
712 |
|
713 function GetVolumePercent(): LongInt; |
|
714 begin |
|
715 GetVolumePercent:= Volume * 100 div MIX_MAX_VOLUME; |
645 end; |
716 end; |
646 |
717 |
647 function ChangeVolume(voldelta: LongInt): LongInt; |
718 function ChangeVolume(voldelta: LongInt): LongInt; |
648 begin |
719 begin |
649 ChangeVolume:= 0; |
720 ChangeVolume:= 0; |
657 Mix_Volume(-1, Volume); |
728 Mix_Volume(-1, Volume); |
658 // get assigned Volume |
729 // get assigned Volume |
659 Volume:= Mix_Volume(-1, -1); |
730 Volume:= Mix_Volume(-1, -1); |
660 if isMusicEnabled then |
731 if isMusicEnabled then |
661 Mix_VolumeMusic(Volume * 4 div 8); |
732 Mix_VolumeMusic(Volume * 4 div 8); |
662 ChangeVolume:= Volume * 100 div MIX_MAX_VOLUME; |
733 ChangeVolume:= GetVolumePercent(); |
663 |
734 |
664 if (isMusicEnabled) then |
735 if (isMusicEnabled) then |
665 if (Volume = 0) then |
736 if (Volume = 0) then |
666 PauseMusic |
737 PauseMusic |
667 else |
738 else |
763 if s[byte(s[0])]='"' then |
834 if s[byte(s[0])]='"' then |
764 Delete(s, byte(s[0]), 1); |
835 Delete(s, byte(s[0]), 1); |
765 CurrentTeam^.voicepack:= AskForVoicepack(s) |
836 CurrentTeam^.voicepack:= AskForVoicepack(s) |
766 end; |
837 end; |
767 |
838 |
768 procedure chMute(var s: shortstring); |
|
769 begin |
|
770 s:= s; // avoid compiler hint |
|
771 MuteAudio; |
|
772 end; |
|
773 |
|
774 procedure preInitModule; |
839 procedure preInitModule; |
775 begin |
840 begin |
776 isMusicEnabled:= true; |
841 isMusicEnabled:= true; |
777 isSoundEnabled:= true; |
842 isSoundEnabled:= true; |
778 cInitVolume:= 100; |
843 cInitVolume:= 100; |