From 0ba3b62efff0432792da2e37ddb9172a85d39d5a Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 17 Mar 2020 13:00:07 +0800 Subject: [PATCH] Improved and fixed the playback of alternative sound files Added a new mode to play_sfall_sound script function. --- artifacts/scripting/sfall function notes.txt | 2 +- artifacts/scripting/sfall opcode list.txt | 4 +- sfall/FalloutEngine.cpp | 9 + sfall/FalloutEngine.h | 7 + sfall/ScriptOps/MiscOps.hpp | 8 +- sfall/Sound.cpp | 278 ++++++++++++------- sfall/Sound.h | 2 +- sfall/main.h | 2 + 8 files changed, 211 insertions(+), 101 deletions(-) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 665bbff8..2ef03b2b 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -66,7 +66,7 @@ get/set_proto_data are used to manipulate the in memory copies of the .pro files the list_xxx functions can be used to loop over all items on a map. list_begin takes an argument telling sfall what you want to list. (Defined in sfall.h) It returns a list pointer, which you iterate through with list_next. Finally, when you've finished with the list use list_end on it. Not calling list_end will result in a memory leak. Alternatively, use list_as_array to get the whole list at once as a temp array variable, which can be looped over using len_array and which you don't need to remember to free afterwards. -play_sfall_sound and stop_sfall_sound are used to play mp3/wav/wma files. The path given is relative to the Fallout folder. Specify loop as 1 to loop the file continuously, or 0 otherwise. If you don't wish to loop, play_sfall_sound returns 0. If you do loop, it returns an id which can be passed back to stop_sfall_sound when you want to stop the effect. All sounds effects will be stopped on game reload, looping or not. These functions do not require 'AllowDShowSound' to be set to 1 in ddraw.ini. +play_sfall_sound and stop_sfall_sound are used to play mp3/wav/wma files. The path given is relative to the Fallout folder. Specify mode as 1 to loop the file continuously, 2 to replace the current background game music with playing the specified file in loop mode, or 0 to play the file once. If you don't wish to loop, play_sfall_sound returns 0. If you do loop, it returns an id which can be passed back to stop_sfall_sound when you want to stop the effect. All sounds effects will be stopped on game reload, looping or not. These functions do not require 'AllowDShowSound' to be set to 1 in ddraw.ini. arrays are created and manipulated with the xxx_array functions. An array must first be created with create_array or temp_array, specifying how many data elements the array can hold. You can store any of ints, floats and strings in an array, and can mix all 3 in a single array. The id returned by create/temp_array can then be used with the other array functions. Arrays are shared between all scripts. (i.e. you can call create_array from one script, and then use the returned id from another script.) They are also saved across savegames. You must remember to free any arrays you create with create_array when you are done with them, or you will leak memory. arrays created with temp_array will be automatically freed at the end of the frame. These functions are safe, in that supplying a bad id or trying to access out of range elements will not crash the script. create_array is the only function that returns a permanent array, all other functions which return arrays (string_split, list_as_array etc,) all return temp arrays. You can use fix_array to make a temp array permanent. diff --git a/artifacts/scripting/sfall opcode list.txt b/artifacts/scripting/sfall opcode list.txt index 5bdd6ace..89700e7e 100644 --- a/artifacts/scripting/sfall opcode list.txt +++ b/artifacts/scripting/sfall opcode list.txt @@ -296,8 +296,8 @@ 0x8228 - int get_attack_type -0x822b - int play_sfall_sound(string file, bool loop) -0x822c - void stop_sfall_sound(int id) +0x822b - int play_sfall_sound(string file, int mode) +0x822c - void stop_sfall_sound(int soundID) 0x8235 - array string_split(string string, string split) 0x8237 - int atoi(string string) diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 44c0c8d2..54723c1d 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -30,6 +30,7 @@ sArt* ptr_art = reinterpret_cast(_art); DWORD* ptr_art_name = reinterpret_cast(_art_name); DWORD* ptr_art_vault_guy_num = reinterpret_cast(_art_vault_guy_num); DWORD* ptr_art_vault_person_nums = reinterpret_cast(_art_vault_person_nums); +DWORD* ptr_background_volume = reinterpret_cast(_background_volume); BYTE** ptr_bckgnd = reinterpret_cast(_bckgnd); DWORD* ptr_black_palette = reinterpret_cast(_black_palette); BYTE* ptr_BlueColor = reinterpret_cast(_BlueColor); @@ -124,6 +125,7 @@ DWORD* ptr_main_window = reinterpret_cast(_main_window); DWORD* ptr_map_elevation = reinterpret_cast(_map_elevation); DWORD* ptr_map_global_vars = reinterpret_cast(_map_global_vars); PathNode** ptr_master_db_handle = reinterpret_cast(_master_db_handle); +DWORD* ptr_master_volume = reinterpret_cast(_master_volume); DWORD* ptr_max = reinterpret_cast(_max); long* ptr_maxScriptNum = reinterpret_cast(_maxScriptNum); DWORD* ptr_Meet_Frank_Horrigan = reinterpret_cast(_Meet_Frank_Horrigan); @@ -186,6 +188,7 @@ DWORD* ptr_scriptListInfo = reinterpret_cast(_scriptListInfo DWORD* ptr_skill_data = reinterpret_cast(_skill_data); const DWORD* ptr_skldxwin = reinterpret_cast(_skldxwin); DWORD* ptr_slot_cursor = reinterpret_cast(_slot_cursor); +DWORD* ptr_sndfx_volume = reinterpret_cast(_sndfx_volume); DWORD* ptr_sneak_working = reinterpret_cast(_sneak_working); // DWORD var char** ptr_sound_music_path1 = reinterpret_cast(_sound_music_path1); char** ptr_sound_music_path2 = reinterpret_cast(_sound_music_path2); @@ -411,6 +414,7 @@ const DWORD GNW_find_ = 0x4D7888; const DWORD GNW95_process_message_ = 0x4C9CF0; const DWORD gsnd_build_weapon_sfx_name_ = 0x451760; const DWORD gsound_background_pause_ = 0x450B50; +const DWORD gsound_background_restart_last_ = 0x450B0C; const DWORD gsound_background_stop_ = 0x450AB4; const DWORD gsound_background_unpause_ = 0x450B64; const DWORD gsound_background_volume_get_set_ = 0x450620; @@ -659,6 +663,7 @@ const DWORD scr_set_ext_param_ = 0x4A3B34; const DWORD scr_set_local_var_ = 0x4A6E58; const DWORD scr_set_objs_ = 0x4A3B0C; const DWORD scr_write_ScriptNode_ = 0x4A5704; +const DWORD set_focus_func_ = 0x4C9438; const DWORD set_game_time_ = 0x4A347C; const DWORD setup_move_timer_win_ = 0x476AB8; const DWORD SexWindow_ = 0x437664; @@ -989,6 +994,10 @@ long __stdcall ScrRemove(long scriptID) { WRAP_WATCOM_CALL1(scr_remove_, scriptID) } +void __stdcall SetFocusFunc(void* func) { + WRAP_WATCOM_CALL1(set_focus_func_, func) +} + void __fastcall RegisterObjectCall(long* target, long* source, void* func, long delay) { WRAP_WATCOM_FCALL4(register_object_call_, target, source, func, delay) } diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index c597a3d2..c1d0909f 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -307,6 +307,7 @@ extern sArt* ptr_art; extern DWORD* ptr_art_name; extern DWORD* ptr_art_vault_guy_num; extern DWORD* ptr_art_vault_person_nums; +extern DWORD* ptr_background_volume; extern BYTE** ptr_bckgnd; extern DWORD* ptr_black_palette; extern BYTE* ptr_BlueColor; @@ -401,6 +402,7 @@ extern DWORD* ptr_main_window; extern DWORD* ptr_map_elevation; extern DWORD* ptr_map_global_vars; extern PathNode** ptr_master_db_handle; +extern DWORD* ptr_master_volume; extern DWORD* ptr_max; extern long* ptr_maxScriptNum; extern DWORD* ptr_Meet_Frank_Horrigan; @@ -464,6 +466,7 @@ extern DWORD* ptr_scriptListInfo; extern DWORD* ptr_skill_data; extern const DWORD* ptr_skldxwin; extern DWORD* ptr_slot_cursor; +extern DWORD* ptr_sndfx_volume; extern DWORD* ptr_sneak_working; // DWORD var extern char** ptr_sound_music_path1; extern char** ptr_sound_music_path2; @@ -670,6 +673,7 @@ extern const DWORD GNW_find_; extern const DWORD GNW95_process_message_; extern const DWORD gsnd_build_weapon_sfx_name_; extern const DWORD gsound_background_pause_; +extern const DWORD gsound_background_restart_last_; extern const DWORD gsound_background_stop_; extern const DWORD gsound_background_unpause_; extern const DWORD gsound_background_volume_get_set_; @@ -927,6 +931,7 @@ extern const DWORD scr_set_ext_param_; extern const DWORD scr_set_local_var_; extern const DWORD scr_set_objs_; extern const DWORD scr_write_ScriptNode_; +extern const DWORD set_focus_func_; extern const DWORD set_game_time_; extern const DWORD setup_move_timer_win_; extern const DWORD SexWindow_; @@ -1149,6 +1154,8 @@ long __stdcall ScrNew(long* scriptID, long sType); long __stdcall ScrRemove(long scriptID); +void __stdcall SetFocusFunc(void* func); + void __fastcall RegisterObjectCall(long* target, long* source, void* func, long delay); long __fastcall ScrGetLocalVar(long sid, long varId, long* value); diff --git a/sfall/ScriptOps/MiscOps.hpp b/sfall/ScriptOps/MiscOps.hpp index 37a6eafc..e4104613 100644 --- a/sfall/ScriptOps/MiscOps.hpp +++ b/sfall/ScriptOps/MiscOps.hpp @@ -904,10 +904,12 @@ skip: static void _stdcall play_sfall_sound2() { const ScriptValue &fileArg = opHandler.arg(0), - &loopArg = opHandler.arg(1); + &modeArg = opHandler.arg(1); - if (fileArg.isString() && loopArg.isInt()) { - DWORD soundID = PlaySfallSound(fileArg.strValue(), loopArg.asBool()); + if (fileArg.isString() && modeArg.isInt()) { + DWORD soundID = 0; + long mode = modeArg.rawValue(); + if (mode >= 0) soundID = PlaySfallSound(fileArg.strValue(), mode); opHandler.setReturn(soundID); } else { OpcodeInvalidArgs("play_sfall_sound"); diff --git a/sfall/Sound.cpp b/sfall/Sound.cpp index 1c200d47..021878e8 100644 --- a/sfall/Sound.cpp +++ b/sfall/Sound.cpp @@ -26,6 +26,26 @@ #define SAFERELEASE(a) { if (a) { a->Release(); } } +enum SoundType : unsigned long { + SNDTYPE_sfx_loop = 0, // sfall + SNDTYPE_sfx_single = 1, // sfall + SNDTYPE_game_sfx = 2, + SNDTYPE_game_master = 3 +}; + +enum SoundMode : long { + SNDMODE_single_play = 0, // uses sfx volume + SNDMODE_loop_play = 1, // uses sfx volume + SNDMODE_music_play = 2, // uses background volume + SNDMODE_engine_music_play = -1 // used when playing game music in an alternative format (not used from scripts) +}; + +enum SoundFlags : unsigned long { + SNDFLAG_looping = 0x10000000, + SNDFLAG_restore = 0x40000000, // restore background game music on stop play + SNDFLAG_engine = 0x80000000 +}; + struct sDSSound { DWORD id; // should be first IGraphBuilder *pGraph; @@ -42,7 +62,7 @@ DWORD playID = 0; DWORD loopID = 0; static HWND soundwindow = 0; -static sDSSound* musicLoopPtr = nullptr; +static sDSSound* backgroundMusic = nullptr; // currently playing sfall background music //static char playingMusicFile[256]; static void FreeSound(sDSSound* sound) { @@ -60,7 +80,7 @@ void WipeSounds() { for (size_t i = 0; i < loopingSounds.size(); i++) FreeSound(loopingSounds[i]); playingSounds.clear(); loopingSounds.clear(); - musicLoopPtr = nullptr; + backgroundMusic = nullptr; playID = 0; loopID = 0; } @@ -69,7 +89,8 @@ LRESULT CALLBACK SoundWndProc(HWND wnd, UINT msg, WPARAM w, LPARAM l) { if (msg == WM_APP) { DWORD id = l; sDSSound* sound = nullptr; - if (id & 0x80000000) { + long index = -1; + if (id & SNDFLAG_looping) { for (size_t i = 0; i < loopingSounds.size(); i++) { if (loopingSounds[i]->id == id) { sound = loopingSounds[i]; @@ -80,28 +101,24 @@ LRESULT CALLBACK SoundWndProc(HWND wnd, UINT msg, WPARAM w, LPARAM l) { for (size_t i = 0; i < playingSounds.size(); i++) { if (playingSounds[i]->id == id) { sound = playingSounds[i]; + index = i; break; } } } - if (!sound) return 0; + LONG e = 0; LONG_PTR p1 = 0, p2 = 0; - while (!FAILED(sound->pEvent->GetEvent(&e, &p1, &p2, 0))) { + if (sound && !FAILED(sound->pEvent->GetEvent(&e, &p1, &p2, 0))) { sound->pEvent->FreeEventParams(e, p1, p2); if (e == EC_COMPLETE) { - if (id & 0x80000000) { + if (id & SNDFLAG_looping) { LONGLONG pos = 0; sound->pSeek->SetPositions(&pos, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning); sound->pControl->Run(); } else { - for (size_t i = 0; i < playingSounds.size(); i++) { - if (playingSounds[i] == sound) { - FreeSound(sound); - playingSounds.erase(playingSounds.begin() + i); - return 0; - } - } + FreeSound(sound); + playingSounds.erase(playingSounds.begin() + index); } } } @@ -115,7 +132,8 @@ static void CreateSndWnd() { if (GraphicsMode == 0) CoInitialize(0); WNDCLASSEX wcx; - memset(&wcx, 0, sizeof(wcx)); + std::memset(&wcx, 0, sizeof(wcx)); + wcx.cbSize = sizeof(wcx); wcx.lpfnWndProc = SoundWndProc; wcx.hInstance = GetModuleHandleA(0); @@ -126,16 +144,40 @@ static void CreateSndWnd() { dlogr(" Done", DL_INIT); } -void __stdcall PauseSfallSound(sDSSound* ptr) { - ptr->pControl->Pause(); +void __stdcall PauseSfallSound(sDSSound* sound) { + sound->pControl->Pause(); } -void __stdcall ResumeSfallSound(sDSSound* ptr) { - ptr->pControl->Run(); +void __stdcall ResumeSfallSound(sDSSound* sound) { + sound->pControl->Run(); +} + +void __stdcall PauseAllSfallSound() { + std::vector::iterator it; + sDSSound* sound = *it; + for (it = loopingSounds.begin(); it != loopingSounds.end(); ++it) { + sound->pControl->Pause(); + } + for (it = playingSounds.begin(); it != playingSounds.end(); ++it) { + sound->pControl->Pause(); + } +} + +void __stdcall ResumeAllSfallSound() { + std::vector::iterator it; + sDSSound* sound = *it; + for (it = loopingSounds.begin(); it != loopingSounds.end(); ++it) { + sound->pControl->Run(); + } + for (it = playingSounds.begin(); it != playingSounds.end(); ++it) { + sound->pControl->Run(); + } } static long CalculateVolumeDB(long masterVolume, long passVolume) { - const int volOffset = -100; // maximum volume + if (masterVolume <= 0 || passVolume <= 0) return -9999; // mute + + const int volOffset = -100; // adjust the maximum volume const int minVolume = -2048; float multiply = (32767.0f / masterVolume); @@ -144,32 +186,34 @@ static long CalculateVolumeDB(long masterVolume, long passVolume) { return static_cast(minVolume - volume) + volOffset; } -static void __cdecl SfallSoundVolume(sDSSound* sound, int type, long passVolume) { - long loopVolume, sfxVolume, masterVolume = *(DWORD*)_master_volume; +/* + master_volume: sound=0 type=game_master passVolume=background_volume + background_volume: sound=backgroundMusic type=background_loop passVolume=background_volume + sfx_volume: sound=0 type=game_sfx passVolume=sndfx_volume + */ +static void __cdecl SfallSoundVolume(sDSSound* sound, SoundType type, long passVolume) { + long volume, sfxVolume, masterVolume = *ptr_master_volume; - if (masterVolume > 0 && passVolume > 0) { - loopVolume = CalculateVolumeDB(masterVolume, passVolume); - if (type = 2) sfxVolume = CalculateVolumeDB(masterVolume, *(DWORD*)_sndfx_volume); - } else { - if (masterVolume == 0) { - loopVolume = sfxVolume = -9999; // mute - } else if (type = 0) { // for music - if (musicLoopPtr) { - StopSfallSound(musicLoopPtr->id); - musicLoopPtr = nullptr; - } - return; - } - } + volume = CalculateVolumeDB(masterVolume, passVolume); + if (type == SNDTYPE_game_master) sfxVolume = CalculateVolumeDB(masterVolume, *ptr_sndfx_volume); if (sound) { - sound->pAudio->put_Volume(loopVolume); + sound->pAudio->put_Volume(volume); } else { - for (DWORD i = 0; i < loopingSounds.size(); i++) { - loopingSounds[i]->pAudio->put_Volume(loopVolume); + if (type == SNDTYPE_game_sfx) sfxVolume = volume; + bool sfx_or_master = (type == SNDTYPE_game_sfx || type == SNDTYPE_game_master); + for (size_t i = 0; i < loopingSounds.size(); i++) { + if (sfx_or_master) { + if ((loopingSounds[i]->id & 0xF0000000) == SNDFLAG_looping) { // only for sfx loop mode + loopingSounds[i]->pAudio->put_Volume(sfxVolume); + continue; + } else + if (type == SNDTYPE_game_sfx) continue; + } + loopingSounds[i]->pAudio->put_Volume(volume); } - if (type = 2) { // sfx - for (DWORD i = 0; i < playingSounds.size(); i++) { + if (sfx_or_master) { + for (size_t i = 0; i < playingSounds.size(); i++) { playingSounds[i]->pAudio->put_Volume(sfxVolume); } } @@ -177,27 +221,29 @@ static void __cdecl SfallSoundVolume(sDSSound* sound, int type, long passVolume) } static bool IsMute(bool type) { - //if (*(DWORD*)_master_volume == 0) return true; + //if (*ptr_master_volume == 0) return true; int value; if (type) { - value = *(DWORD*)_background_volume; + value = *ptr_background_volume; } else { - value = *(DWORD*)_sndfx_volume; + value = *ptr_sndfx_volume; } return (value == 0); } -static sDSSound* PlayingSound(wchar_t* path, bool loop) { +/* + single_play: mode 0 - single sound playback (with sound overlay) + loop_play: mode 1 - loop sound playback (with sound overlay) + music_play: mode 2 - loop sound playback with the background game music turned off +*/ +static sDSSound* PlayingSound(wchar_t* path, SoundMode mode) { if (!soundwindow) CreateSndWnd(); - if (IsMute(loop)) return nullptr; + bool isLoop = (mode != SNDMODE_single_play); + if (IsMute(isLoop)) return nullptr; sDSSound* sound = new sDSSound(); - DWORD id = (loop) ? ++loopID : ++playID; - if (loop) id |= 0x80000000; - sound->id = id; - HRESULT hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC, IID_IGraphBuilder, (void**)&sound->pGraph); if (hr != S_OK) { dlog_f("Error CoCreateInstance: %d", DL_INIT, hr); @@ -205,24 +251,38 @@ static sDSSound* PlayingSound(wchar_t* path, bool loop) { } sound->pGraph->QueryInterface(IID_IMediaControl, (void**)&sound->pControl); - if (loop) + if (isLoop) sound->pGraph->QueryInterface(IID_IMediaSeeking, (void**)&sound->pSeek); else sound->pSeek = nullptr; sound->pGraph->QueryInterface(IID_IMediaEventEx, (void**)&sound->pEvent); - sound->pEvent->SetNotifyWindow((OAHWND)soundwindow, WM_APP, id); sound->pGraph->QueryInterface(IID_IBasicAudio, (void**)&sound->pAudio); + sound->id = (isLoop) ? ++loopID : ++playID; + if (isLoop) sound->id |= SNDFLAG_looping; // sfx loop sound + + if (mode == SNDMODE_music_play) { + sound->id |= SNDFLAG_restore; // restore background game music on stop + if (backgroundMusic) + StopSfallSound(backgroundMusic->id); + else { + __asm call gsound_background_stop_; + } + backgroundMusic = sound; + } + else if (mode == SNDMODE_engine_music_play) sound->id |= SNDFLAG_engine; // engine play + + sound->pEvent->SetNotifyWindow((OAHWND)soundwindow, WM_APP, sound->id); sound->pControl->RenderFile(path); sound->pControl->Run(); - if (loop) { + if (isLoop) { loopingSounds.push_back(sound); - SfallSoundVolume(sound, 0, *(DWORD*)_background_volume); // music + SfallSoundVolume(sound, SNDTYPE_sfx_loop, (mode == SNDMODE_loop_play) ? *ptr_sndfx_volume : *ptr_background_volume); } else { playingSounds.push_back(sound); - SfallSoundVolume(sound, 1, *(DWORD*)_sndfx_volume); + SfallSoundVolume(sound, SNDTYPE_sfx_single, *ptr_sndfx_volume); } return sound; } @@ -245,19 +305,19 @@ static bool __cdecl SoundFileLoad(DWORD called, const char* path) { } bool music = (called == 0x45092B); // from gsound_background_play_ - if (music && musicLoopPtr != nullptr) { + if (music && backgroundMusic != nullptr) { //if (found && strcmp(path, playingMusicFile) == 0) return true; // don't stop music - StopSfallSound(musicLoopPtr->id); - musicLoopPtr = nullptr; + StopSfallSound(backgroundMusic->id); + backgroundMusic = nullptr; } if (!isExist) return false; if (music) { //strcpy_s(playingMusicFile, path); - musicLoopPtr = PlayingSound(buf, true); // music loop - if (!musicLoopPtr) return false; + backgroundMusic = PlayingSound(buf, SNDMODE_engine_music_play); // background music loop + if (!backgroundMusic) return false; } else { - if (!PlayingSound(buf, false)) return false; + if (!PlayingSound(buf, SNDMODE_single_play)) return false; } return true; } @@ -273,21 +333,24 @@ static void __fastcall MakeMusicPath(const char* file) { SoundFileLoad(0x45092B, pathBuf); } -DWORD __stdcall PlaySfallSound(const char* path, bool loop) { +DWORD __stdcall PlaySfallSound(const char* path, long mode) { wchar_t buf[256]; mbstowcs_s(0, buf, path, 256); - sDSSound* sound = PlayingSound(buf, loop); - return (loop && sound) ? sound->id : 0; + sDSSound* sound = PlayingSound(buf, (SoundMode)mode); + return (mode && sound) ? sound->id : 0; } void __stdcall StopSfallSound(DWORD id) { - if (!id) return; + if (!(id & 0xFFFFFF)) return; for (size_t i = 0; i < loopingSounds.size(); i++) { if (loopingSounds[i]->id == id) { sDSSound* sound = loopingSounds[i]; sound->pControl->Stop(); FreeSound(sound); loopingSounds.erase(loopingSounds.begin() + i); + if (!(id & SNDFLAG_engine) && id & SNDFLAG_restore) { + __asm call gsound_background_restart_last_; + } return; } } @@ -329,16 +392,16 @@ static void __declspec(naked) gsound_background_play_hook() { static void __declspec(naked) gmovie_play_hook_stop() { __asm { - mov eax, musicLoopPtr; + mov eax, backgroundMusic; test eax, eax; jz skip; - mov eax, [eax]; // musicLoopPtr->id + mov eax, [eax]; // backgroundMusic->id push ecx; push edx; push eax; call StopSfallSound; xor eax, eax; - mov musicLoopPtr, eax; + mov backgroundMusic, eax; pop edx; pop ecx; retn; @@ -349,35 +412,31 @@ skip: static void __declspec(naked) gmovie_play_hook_pause() { __asm { - mov eax, musicLoopPtr; - test eax, eax; - jz skip; push ecx; push edx; - push eax; - call PauseSfallSound; + call PauseAllSfallSound; pop edx; pop ecx; - retn; -skip: + cmp dword ptr backgroundMusic, 0; + jnz skip; jmp gsound_background_pause_; +skip: + retn; } } static void __declspec(naked) gmovie_play_hook_unpause() { __asm { - mov eax, musicLoopPtr; - test eax, eax; - jz skip; push ecx; push edx; - push eax; - call ResumeSfallSound; + call ResumeAllSfallSound; pop edx; pop ecx; - retn; -skip: + cmp dword ptr backgroundMusic, 0; + jnz skip; jmp gsound_background_unpause_; +skip: + retn; } } @@ -385,13 +444,13 @@ static void __declspec(naked) gsound_background_volume_set_hack() { __asm { mov dword ptr ds:[_background_volume], eax; push ecx; - mov ecx, musicLoopPtr; + mov ecx, backgroundMusic; test ecx, ecx; jz skip; push edx; push eax; - push 0; - push ecx; + push 0; // SNDTYPE_sfx_loop + push ecx; // set volume for background music call SfallSoundVolume; add esp, 8; pop eax; @@ -409,8 +468,8 @@ static void __declspec(naked) gsound_master_volume_set_hack() { push ecx; push edx; push dword ptr ds:[_background_volume]; - push 2; - push 0; + push 3; // SNDTYPE_game_master + push 0; // set volume for all sounds call SfallSoundVolume; add esp, 12; pop edx; @@ -420,6 +479,33 @@ static void __declspec(naked) gsound_master_volume_set_hack() { } } +static void __declspec(naked) gsound_set_sfx_volume_hack() { + __asm { + push ecx; + push edx; + mov dword ptr ds:[_sndfx_volume], eax; + push eax; + push 2; // SNDTYPE_game_sfx + push 0; // set volume for all sounds + call SfallSoundVolume; + add esp, 12; + pop edx; + pop ecx; + retn; + } +} + +static void SoundLostFocus() { + long isActive; + __asm mov isActive, eax; + + if (isActive) { + ResumeAllSfallSound(); + } else { + PauseAllSfallSound(); + } +} + /////////////////////////////////////////////////////////////////////////////// static char attackerSnd[9] = {0}; @@ -471,15 +557,19 @@ end: } void SoundInit() { - int allowDShowSound = GetConfigInt("Sound", "AllowDShowSound", 0); - if (allowDShowSound > 0) { + HookCall(0x44E816, gmovie_play_hook_pause); + HookCall(0x44EA84, gmovie_play_hook_unpause); + MakeCall(0x450525, gsound_background_volume_set_hack); + MakeCall(0x4503CA, gsound_master_volume_set_hack, 1); + MakeCall(0x45042C, gsound_set_sfx_volume_hack); + + // Pause and resume sound playback when the game loses focus + //SetFocusFunc(SoundLostFocus); + + if (int allowDShowSound = GetConfigInt("Sound", "AllowDShowSound", 0) > 0) { MakeJump(0x4AD499, soundLoad_hack); - HookCall(0x445280, gmovie_play_hook_stop); // only play looping music - HookCall(0x44E80A, gmovie_play_hook_stop); - HookCall(0x44E816, gmovie_play_hook_pause); - HookCall(0x44EA84, gmovie_play_hook_unpause); - MakeCall(0x450525, gsound_background_volume_set_hack); - MakeCall(0x4503CA, gsound_master_volume_set_hack, 1); + HookCall(0x44E80A, gmovie_play_hook_stop); // only play looping music + HookCall(0x445280, gmovie_play_hook_stop); if (allowDShowSound > 1) { HookCall(0x450851, gsound_background_play_hook); } diff --git a/sfall/Sound.h b/sfall/Sound.h index 13bfd98f..052d92b5 100644 --- a/sfall/Sound.h +++ b/sfall/Sound.h @@ -21,6 +21,6 @@ void SoundInit(); void SoundExit(); -DWORD __stdcall PlaySfallSound(const char* path, bool loop); +DWORD __stdcall PlaySfallSound(const char* path, long mode); void __stdcall StopSfallSound(DWORD id); void WipeSounds(); diff --git a/sfall/main.h b/sfall/main.h index 669bc222..ef57a64e 100644 --- a/sfall/main.h +++ b/sfall/main.h @@ -24,7 +24,9 @@ #include #include +#include #include +#include #include #include "SafeWrite.h"