mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Improved and fixed the playback of alternative sound files
Added a new mode to play_sfall_sound script function.
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -30,6 +30,7 @@ sArt* ptr_art = reinterpret_cast<sArt*>(_art);
|
||||
DWORD* ptr_art_name = reinterpret_cast<DWORD*>(_art_name);
|
||||
DWORD* ptr_art_vault_guy_num = reinterpret_cast<DWORD*>(_art_vault_guy_num);
|
||||
DWORD* ptr_art_vault_person_nums = reinterpret_cast<DWORD*>(_art_vault_person_nums);
|
||||
DWORD* ptr_background_volume = reinterpret_cast<DWORD*>(_background_volume);
|
||||
BYTE** ptr_bckgnd = reinterpret_cast<BYTE**>(_bckgnd);
|
||||
DWORD* ptr_black_palette = reinterpret_cast<DWORD*>(_black_palette);
|
||||
BYTE* ptr_BlueColor = reinterpret_cast<BYTE*>(_BlueColor);
|
||||
@@ -124,6 +125,7 @@ DWORD* ptr_main_window = reinterpret_cast<DWORD*>(_main_window);
|
||||
DWORD* ptr_map_elevation = reinterpret_cast<DWORD*>(_map_elevation);
|
||||
DWORD* ptr_map_global_vars = reinterpret_cast<DWORD*>(_map_global_vars);
|
||||
PathNode** ptr_master_db_handle = reinterpret_cast<PathNode**>(_master_db_handle);
|
||||
DWORD* ptr_master_volume = reinterpret_cast<DWORD*>(_master_volume);
|
||||
DWORD* ptr_max = reinterpret_cast<DWORD*>(_max);
|
||||
long* ptr_maxScriptNum = reinterpret_cast<long*>(_maxScriptNum);
|
||||
DWORD* ptr_Meet_Frank_Horrigan = reinterpret_cast<DWORD*>(_Meet_Frank_Horrigan);
|
||||
@@ -186,6 +188,7 @@ DWORD* ptr_scriptListInfo = reinterpret_cast<DWORD*>(_scriptListInfo
|
||||
DWORD* ptr_skill_data = reinterpret_cast<DWORD*>(_skill_data);
|
||||
const DWORD* ptr_skldxwin = reinterpret_cast<DWORD*>(_skldxwin);
|
||||
DWORD* ptr_slot_cursor = reinterpret_cast<DWORD*>(_slot_cursor);
|
||||
DWORD* ptr_sndfx_volume = reinterpret_cast<DWORD*>(_sndfx_volume);
|
||||
DWORD* ptr_sneak_working = reinterpret_cast<DWORD*>(_sneak_working); // DWORD var
|
||||
char** ptr_sound_music_path1 = reinterpret_cast<char**>(_sound_music_path1);
|
||||
char** ptr_sound_music_path2 = reinterpret_cast<char**>(_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)
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
+184
-94
@@ -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<sDSSound*>::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<sDSSound*>::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<long>(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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <cstdint>
|
||||
|
||||
#include "SafeWrite.h"
|
||||
|
||||
Reference in New Issue
Block a user