/* * sound.d * * Sound and music functions * * - Requires Ikarus, LeGo (Anim8), searchVobs.d, insertAnything.d * - Compatible with Gothic 1 and Gothic 2 * - Initialization with restoreMasterVolumeSoundsToDefault() and/or restoreVolumeMusicToDefault() recommended * * When using the setVolumne-functions or fadeOut-functions, make sure to call * restoreMasterVolumeSoundsToDefault() and/or restoreVolumeMusicToDefault() * in Init_Global to restore the volume on loading/new game! * * The volumes will always be reset to their defaults after loading a game. Thus, this script does not take care of * maintaining the volume over saving and loading a game. * * Keep in mind, that you cannot call the fadeOut-functions from startup. LeGo has to be initialized first. The LeGo * package GameState can compensate for that. * * * func void stopAllSounds() * func void fadeOutAllSounds(int fadeOutMS, int waitMS, int fadeInMS, int killSounds) * func int getMasterVolumeSounds() * func void setMasterVolumeSounds(int volume) * func void restoreMasterVolumeSoundsToDefault() * * func void stopMusic() * func void fadeOutMusic(int fadeOutMS, int waitMS, int fadeInMS, int killMusic) * func void playMusic(string music, int transition) * func int getVolumeMusic() * func void setVolumeMusic(int volume) * func void restoreVolumeMusicToDefault() * * func void setMusicZoneTheme(string vobName, string musicTheme) * func void setCurrentMusicZoneTheme(string musicTheme) * func string getCurrentMusicZoneTheme() * func void setAllMusicZoneThemes(string musicTheme) */ /* * Stop all effect and speech sounds of the game instantly */ func void stopAllSounds() { MEM_InitAll(); const int zsound_G1 = 9236044; //0x8CEE4C const int zsound_G2 = 10072124; //0x99B03C const int zCSndSys_MSS__RemoveAllActiveSounds_G1 = 5112224; //0x4E01A0 const int zCSndSys_MSS__RemoveAllActiveSounds_G2 = 5167008; //0x4ED7A0 var int zsoundPtr; zsoundPtr = MEM_ReadInt(MEMINT_SwitchG1G2(zsound_G1, zsound_G2)); const int call = 0; if (CALL_Begin(call)) { CALL__thiscall(_@(zsoundPtr), MEMINT_SwitchG1G2(zCSndSys_MSS__RemoveAllActiveSounds_G1, zCSndSys_MSS__RemoveAllActiveSounds_G2)); call = CALL_End(); }; }; /* * Get master volume sound */ func int getMasterVolumeSounds() { const int zCSndSys_MSS__prefs_G1 = 8837192; //0x86D848 const int zCSndSys_MSS__prefs_G2 = 9249512; //0x8D22E8 return MEM_ReadInt(MEMINT_SwitchG1G2(zCSndSys_MSS__prefs_G1, zCSndSys_MSS__prefs_G2)); }; /* * Backup default master volume sound */ func int getMasterVolumeSoundsDefault() { const int soundDefVol = 0; if (!soundDefVol) { soundDefVol = getMasterVolumeSounds(); }; return soundDefVol; }; /* * Set master volume of sounds * Caution: This control differs from the volume settings in the menu, be sure to always reset it! */ func void setMasterVolumeSounds(var int volume) { const int zsound_G1 = 9236044; //0x8CEE4C const int zsound_G2 = 10072124; //0x99B03C const int zCSndSys_MSS__SetMasterVolume_G1 = 5112544; //0x4E02E0 const int zCSndSys_MSS__SetMasterVolume_G2 = 5167328; //0x4ED8E0 const int mss32_AILptr_G1 = 8838412; //0x86DD0C const int mss32_AILptr_G2 = 9251444; //0x8D2A74 // Prevent crash by checking if sound was initialized (if sound is disabled) if (!MEMINT_SwitchG1G2(MEM_ReadInt(mss32_AILptr_G1), MEM_ReadInt(mss32_AILptr_G2))) { return; }; // Backup default volume before changing it var int i; i = getMasterVolumeSoundsDefault(); var int zsoundPtr; zsoundPtr = MEM_ReadInt(MEMINT_SwitchG1G2(zsound_G1, zsound_G2)); const int call = 0; if (CALL_Begin(call)) { CALL_FloatParam(_@(volume)); CALL__thiscall(_@(zsoundPtr), MEMINT_SwitchG1G2(zCSndSys_MSS__SetMasterVolume_G1, zCSndSys_MSS__SetMasterVolume_G2)); call = CALL_End(); }; }; /* * Restore default sound master volume * Call this function from Init_Global to ensure working sound after loading */ func void restoreMasterVolumeSoundsToDefault() { setMasterVolumeSounds(getMasterVolumeSoundsDefault()); }; /* * Fade out all sounds * Leave sound muted indefinitely by setting fadeInMS to -1 */ func void fadeOutAllSounds(var int fadeOutMS, var int waitMS, var int fadeInMS, var int killSounds) { // Retrieve and backup master volume var int sVol; sVol = getMasterVolumeSounds(); // Start fade out var int a8; a8 = Anim8_NewExt(sVol, soundFadeHandler, killSounds, TRUE); Anim8_RemoveIfEmpty(a8, TRUE); Anim8(a8, FLOATNULL, fadeOutMS, A8_SlowEnd); Anim8q(a8, FLOATNULL, waitMS, A8_Wait); if (fadeInMS != -1) { Anim8q(a8, sVol, fadeInMS, A8_SlowStart); }; }; func void soundFadeHandler(var int killSounds, var int value) { // Once quiet: Kill all sounds if desired if (!value) && (killSounds) { stopAllSounds(); }; setMasterVolumeSounds(value); }; /* * Stop the music instantly */ func void stopMusic() { MEM_InitAll(); const int zmusic_G1 = 8836220; //0x86D47C const int zmusic_G2 = 9248532; //0x8D1F14 const int zCMusicSys_DirectMusic__Stop_G1 = 5098480; //0x4DCBF0 const int zCMusicSys_DirectMusic__Stop_G2 = 5152544; //0x4E9F20 const int zCMusicSystem__s_musicSystemDisabled_G1 = 8836224; //0x86D480 const int zCMusicSystem__s_musicSystemDisabled_G2 = 9248536; //0x8D1F18 // Prevent crash by checking if music system was initialized (if music is disabled) if (MEMINT_SwitchG1G2(MEM_ReadInt(zCMusicSystem__s_musicSystemDisabled_G1), MEM_ReadInt(zCMusicSystem__s_musicSystemDisabled_G2))) { return; }; var int zmusicPtr; zmusicPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zmusic_G1), MEM_ReadInt(zmusic_G2)); const int call = 0; if (CALL_Begin(call)) { CALL__thiscall(_@(zmusicPtr), MEMINT_SwitchG1G2(zCMusicSys_DirectMusic__Stop_G1, zCMusicSys_DirectMusic__Stop_G2)); call = CALL_End(); }; }; /* * Get music volume */ func int getVolumeMusic() { const int zmusic_G1 = 8836220; //0x86D47C const int zmusic_G2 = 9248532; //0x8D1F14 const int zCMusicSys_DirectMusic_volume_offset = 12; //0Ch same for G1 and G2 var int zmusicPtr; zmusicPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zmusic_G1), MEM_ReadInt(zmusic_G2)); return MEM_ReadInt(zmusicPtr+zCMusicSys_DirectMusic_volume_offset); }; /* * Backup default music volume */ func int getVolumeMusicDefault() { const int musicDefVol = 0; if (!musicDefVol) { musicDefVol = getVolumeMusic(); }; return musicDefVol; }; /* * Set volume of music * Caution: This control differs from the volume settings in the menu, be sure to always reset it! */ func void setVolumeMusic(var int volume) { const int zmusic_G1 = 8836220; //0x86D47C const int zmusic_G2 = 9248532; //0x8D1F14 const int zCMusicSys_DirectMusic__SetVolume_G1 = 5098624; //0x4DCC80 const int zCMusicSys_DirectMusic__SetVolume_G2 = 5152720; //0x4E9FD0 const int zCMusicSystem__s_musicSystemDisabled_G1 = 8836224; //0x86D480 const int zCMusicSystem__s_musicSystemDisabled_G2 = 9248536; //0x8D1F18 // Prevent crash by checking if music system was initialized (if music is disabled) if (MEMINT_SwitchG1G2(MEM_ReadInt(zCMusicSystem__s_musicSystemDisabled_G1), MEM_ReadInt(zCMusicSystem__s_musicSystemDisabled_G2))) { return; }; // Backup default volume before changing it var int i; i = getVolumeMusicDefault(); var int zmusicPtr; zmusicPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zmusic_G1), MEM_ReadInt(zmusic_G2)); const int call = 0; if (CALL_Begin(call)) { CALL_FloatParam(_@(volume)); CALL__thiscall(_@(zmusicPtr), MEMINT_SwitchG1G2(zCMusicSys_DirectMusic__SetVolume_G1, zCMusicSys_DirectMusic__SetVolume_G2)); call = CALL_End(); }; }; /* * Restore default music volume * Call this function from Init_Global to ensure working music after loading */ func void restoreVolumeMusicToDefault() { setVolumeMusic(getVolumeMusicDefault()); }; /* * Fade out the music * Leave music muted indefinitely by setting fadeInMS to -1 */ func void fadeOutMusic(var int fadeOutMS, var int waitMS, var int fadeInMS, var int killMusic) { // Retrieve and backup music volume var int mVol; mVol = getVolumeMusic(); // Start fade out var int a8; a8 = Anim8_NewExt(mVol, musicFadeHandler, killMusic, TRUE); Anim8_RemoveIfEmpty(a8, TRUE); Anim8(a8, FLOATNULL, fadeOutMS, A8_SlowEnd); Anim8q(a8, FLOATNULL, waitMS, A8_Wait); if (fadeInMS != -1) { Anim8q(a8, mVol, fadeInMS, A8_SlowStart); }; }; func void musicFadeHandler(var int killMusic, var int value) { // Once quiet: Kill music if desired if (!value) && (killMusic) { stopMusic(); }; setVolumeMusic(value); }; /* * Play music by script instance, e.g. "XAR_Day_Std" * The second argument may be either be 0 (musical transition?), 1 (?) or 2 (some thing like fade out/fade in?) */ func void playMusic(var string music, var int transition) { const int zmusic_G1 = 8836220; //0x86D47C const int zmusic_G2 = 9248532; //0x8D1F14 const int zCMusicSys_DirectMusic__PlayThemeByScript_G1 = 5093456; //0x4DB850 const int zCMusicSys_DirectMusic__PlayThemeByScript_G2 = 5147312; //0x4E8AB0 var int zmusicPtr; zmusicPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zmusic_G1), MEM_ReadInt(zmusic_G2)); var int musicPtr; musicPtr = _@s(music); var int zero; const int call = 0; if (CALL_Begin(call)) { CALL_PtrParam(_@(zero)); // Some pointer CALL_IntParam(_@(transition)); // zTMus_TransType: either 0, 1 or 2 CALL_PtrParam(_@(musicPtr)); CALL__thiscall(_@(zmusicPtr), MEMINT_SwitchG1G2(zCMusicSys_DirectMusic__PlayThemeByScript_G1, zCMusicSys_DirectMusic__PlayThemeByScript_G2)); call = CALL_End(); }; }; /* * Overwrite the music theme of a music zone * * This function will permanently change the music theme for a certain music zone. This change is preserved over * saving/loading, but not across saves. * The first parameter is the object name of the oCZoneMusic vob. * The second parameter is the new post fix identifying the music theme, e.g. "XAR" * * The transition in music will be instant (given that the player is in the affected zone). */ func void setMusicZoneTheme(var string vobName, var string musicTheme) { // Find all vobs of this zone, there are multiple! var int arrPtr; arrPtr = MEM_SearchAllVobsByName(vobName); // Build new vob name var string newName; newName = ConcatStrings(STR_Prefix(vobName, STR_Len(vobName)-3), musicTheme); // Iterate over all music zones and exchange their identifier var zCArray arr; arr = _^(arrPtr); repeat(j, arr.numInArray); var int j; var int vobPtr; vobPtr = MEM_ArrayRead(arrPtr, j); MEM_RenameVob(vobPtr, newName); end; // Free array MEM_ArrayFree(arrPtr); }; /* * Overwrite the music theme of the current music zone */ func void setCurrentMusicZoneTheme(var string musicTheme) { if (!MEM_ReadInt(oCZoneMusic__s_musiczone_Address)) { MEM_Warn("No music zone active. No changes performed."); return; }; // Not only change the current oCZoneMusic, but all matching ones in the area var zCObject vob; vob = _^(MEM_ReadInt(oCZoneMusic__s_musiczone_Address)); setMusicZoneTheme(vob.objectName, musicTheme); }; /* * Get music theme of current music zone (as a prior backup for setCurrentMusicZoneTheme above) */ func string getCurrentMusicZoneTheme() { if (!MEM_ReadInt(oCZoneMusic__s_musiczone_Address)) { MEM_Warn("No music zone active."); return ""; }; var zCObject vob; vob = _^(MEM_ReadInt(oCZoneMusic__s_musiczone_Address)); return STR_SubStr(vob.objectName, STR_Len(vob.objectName)-3, 3); }; /* * Overwrite the music theme of all music zones */ func void setAllMusicZoneThemes(var string musicTheme) { var int arrPtr; arrPtr = MEM_ArrayCreate(); if (SearchVobsByClass("oCZoneMusic", arrPtr)) { // Iterate over all oCZoneMusic vobs var zCArray arr; arr = _^(arrPtr); repeat(i, arr.numInArray); var int i; var int vobPtr; vobPtr = MEM_ArrayRead(arrPtr, i); var zCObject vob; vob = _^(vobPtr); // Build new vob name var string vobName; vobName = vob.objectName; var string newName; newName = ConcatStrings(STR_Prefix(vobName, STR_Len(vobName)-3), musicTheme); // Exchange music theme identifier MEM_RenameVob(vobPtr, newName); end; }; // Free array MEM_ArrayFree(arrPtr); };