- reworked music interface a bit.

Conmsidering how hard it is in Duke Nukem based games to modify the level music, there is now a setting for this in mussetting.txt to make the job easier and even allow setting level music in Redneck Rampage without replacing game data.
This commit is contained in:
Christoph Oelckers 2019-11-12 00:43:07 +01:00
parent 022c074ece
commit 22ccea8677
11 changed files with 82 additions and 54 deletions

View file

@ -2099,11 +2099,16 @@ int sndTryPlaySpecialMusic(int nMusic)
{ {
int nEpisode = nMusic/kMaxLevels; int nEpisode = nMusic/kMaxLevels;
int nLevel = nMusic%kMaxLevels; int nLevel = nMusic%kMaxLevels;
if (!sndPlaySong(gEpisodeInfo[nEpisode].at28[nLevel].atd0, true)) if (sndPlaySong(gEpisodeInfo[nEpisode].at28[nLevel].at0, gEpisodeInfo[nEpisode].at28[nLevel].atd0, true))
{ {
strncpy(gGameOptions.zLevelSong, gEpisodeInfo[nEpisode].at28[nLevel].atd0, BMAX_PATH); strncpy(gGameOptions.zLevelSong, gEpisodeInfo[nEpisode].at28[nLevel].atd0, BMAX_PATH);
return 0; return 0;
} }
else
{
// Unable to stat the music.
*gGameOptions.zLevelSong = 0;
}
return 1; return 1;
} }

View file

@ -403,9 +403,10 @@ bool levelTryPlayMusic(int nEpisode, int nLevel, bool bSetLevelSong)
snprintf(buffer, BMAX_PATH, "blood%02i.ogg", gEpisodeInfo[nEpisode].at28[nLevel].ate0); snprintf(buffer, BMAX_PATH, "blood%02i.ogg", gEpisodeInfo[nEpisode].at28[nLevel].ate0);
else else
strncpy(buffer, gEpisodeInfo[nEpisode].at28[nLevel].atd0, BMAX_PATH); strncpy(buffer, gEpisodeInfo[nEpisode].at28[nLevel].atd0, BMAX_PATH);
bool bReturn = !!sndPlaySong(buffer, true); bool bReturn = !!sndPlaySong(gEpisodeInfo[nEpisode].at28[nLevel].atd0, buffer, true);
if (!bReturn || bSetLevelSong) if (bReturn || bSetLevelSong)
strncpy(gGameOptions.zLevelSong, buffer, BMAX_PATH); strncpy(gGameOptions.zLevelSong, buffer, BMAX_PATH);
else *gGameOptions.zLevelSong = 0;
return bReturn; return bReturn;
} }

View file

@ -1793,7 +1793,7 @@ void UpdateMusicToggle(CGameMenuItemZBool *pItem)
else else
{ {
if (gGameStarted || gDemo.at1) if (gGameStarted || gDemo.at1)
sndPlaySong(gGameOptions.zLevelSong, true); sndPlaySong("*", gGameOptions.zLevelSong, true);
} }
} }
@ -1847,7 +1847,7 @@ void SetSound(CGameMenuItemChain *pItem)
sfxInit(); sfxInit();
if (mus_enabled && (gGameStarted || gDemo.at1)) if (mus_enabled && (gGameStarted || gDemo.at1))
sndPlaySong(gGameOptions.zLevelSong, true); sndPlaySong("*", gGameOptions.zLevelSong, true);
} }
void PreDrawSound(CGameMenuItem *pItem) void PreDrawSound(CGameMenuItem *pItem)

View file

@ -368,7 +368,7 @@ static int osdcmd_restartsound(osdcmdptr_t UNUSED(parm))
sfxInit(); sfxInit();
if (MusicEnabled() && (gGameStarted || gDemo.at1)) if (MusicEnabled() && (gGameStarted || gDemo.at1))
sndPlaySong(gGameOptions.zLevelSong, true); sndPlaySong(nullptr, "*", true);
return OSDCMD_OK; return OSDCMD_OK;
} }

View file

@ -82,7 +82,7 @@ int nSongSize;
bool bWaveMusic; bool bWaveMusic;
int nWaveMusicHandle; int nWaveMusicHandle;
int sndPlaySong(const char *songName, bool bLoop) int sndPlaySong(const char *, const char* songName, bool bLoop)
{ {
if (!MusicEnabled()) if (!MusicEnabled())
return 0; return 0;
@ -225,13 +225,9 @@ void sndStopSong(void)
nSongSize = 0; nSongSize = 0;
} }
#else #else
int sndPlaySong(const char* songName, bool bLoop) int sndPlaySong(const char *mapname, const char* songName, bool bLoop)
{ {
if (!MusicEnabled()) return Mus_Play(mapname, songName, bLoop);
return 0;
Mus_Play(songName, bLoop);
return 0;
} }
bool sndIsSongPlaying(void) bool sndIsSongPlaying(void)

View file

@ -44,7 +44,7 @@ struct SFX
}; };
int sndGetRate(int format); int sndGetRate(int format);
int sndPlaySong(const char *songName, bool bLoop); int sndPlaySong(const char *mapname, const char *songName, bool bLoop);
bool sndIsSongPlaying(void); bool sndIsSongPlaying(void);
void sndFadeSong(int nTime); void sndFadeSong(int nTime);
void sndSetMusicVolume(int nVolume); void sndSetMusicVolume(int nVolume);

View file

@ -73,6 +73,7 @@ MusPlayingInfo mus_playing;
MusicAliasMap MusicAliases; MusicAliasMap MusicAliases;
MidiDeviceMap MidiDevices; MidiDeviceMap MidiDevices;
MusicVolumeMap MusicVolumes; MusicVolumeMap MusicVolumes;
MusicAliasMap LevelMusicAliases;
bool MusicPaused; bool MusicPaused;
//========================================================================== //==========================================================================
// //
@ -553,9 +554,36 @@ CCMD (stopmus)
mus_playing.LastSong = ""; // forget the last played song so that it won't get restarted if some volume changes occur mus_playing.LastSong = ""; // forget the last played song so that it won't get restarted if some volume changes occur
} }
void Mus_Play(const char *fn, bool loop) static FString lastMusicLevel, lastMusic;
int Mus_Play(const char *mapname, const char *fn, bool loop)
{ {
// Store the requested names for resuming.
lastMusicLevel = mapname;
lastMusic = fn;
if (!MusicEnabled())
{
return 0;
}
// A restart was requested. Ignore the music name being passed and just try tp restart what got here last.
if (*mapname == '*')
{
mapname = lastMusicLevel.GetChars();
fn = lastMusic.GetChars();
}
// Allow per level music substitution.
// Unlike some other engines like ZDoom or even Blood which use definition files, the music names in Duke Nukem are being defined in a CON script, making direct replacement a lot harder.
// For most cases using $musicalias would be sufficient, but that method only works if a level actually has some music defined at all.
// This way it can be done with an add-on definition lump even in cases like Redneck Rampage where no music definitions exist or where music gets reused for multiple levels but replacement is wanted individually.
if (mapname && *mapname)
{
if (*mapname == '/') mapname++;
FName *check = LevelMusicAliases.CheckKey(FName(mapname, true));
if (check) fn = check->GetChars();
}
S_ChangeMusic(fn, 0, loop, true); S_ChangeMusic(fn, 0, loop, true);
return mus_playing.handle != nullptr;
} }
void Mus_Stop() void Mus_Stop()

View file

@ -50,11 +50,13 @@ enum SICommands
SI_MusicVolume, SI_MusicVolume,
SI_MidiDevice, SI_MidiDevice,
SI_MusicAlias, SI_MusicAlias,
SI_LevelMusic,
}; };
// This specifies whether Timidity or Windows playback is preferred for a certain song (only useful for Windows.) // This specifies whether Timidity or Windows playback is preferred for a certain song (only useful for Windows.)
extern MusicAliasMap MusicAliases; extern MusicAliasMap MusicAliases;
extern MusicAliasMap LevelMusicAliases;
extern MidiDeviceMap MidiDevices; extern MidiDeviceMap MidiDevices;
extern MusicVolumeMap MusicVolumes; extern MusicVolumeMap MusicVolumes;
@ -76,6 +78,7 @@ static const char *SICommandStrings[] =
"$musicvolume", "$musicvolume",
"$mididevice", "$mididevice",
"$musicalias", "$musicalias",
"$levelmusic",
NULL NULL
}; };
@ -167,6 +170,20 @@ static void S_AddSNDINFO (int lump)
} }
break; break;
case SI_LevelMusic: {
sc.MustGetString();
FName alias = sc.String;
sc.MustGetString();
FName mapped = sc.String;
// only set the alias if the lump it maps to exists.
if (mapped == NAME_None || fileSystem.FindFile(sc.String) >= 0)
{
LevelMusicAliases[alias] = mapped;
}
}
break;
case SI_MidiDevice: { case SI_MidiDevice: {
sc.MustGetString(); sc.MustGetString();
FName nm = sc.String; FName nm = sc.String;

View file

@ -3,6 +3,6 @@
// Totally minimalistic interface - should be all the game modules need. // Totally minimalistic interface - should be all the game modules need.
void Mus_Init(); void Mus_Init();
void Mus_Play(const char *fn, bool loop); int Mus_Play(const char *mapname, const char *fn, bool loop);
void Mus_Stop(); void Mus_Stop();
void Mus_SetPaused(bool on); void Mus_SetPaused(bool on);

View file

@ -204,8 +204,8 @@ void S_MenuSound(void)
S_PlaySound(s); S_PlaySound(s);
} }
#if 0 #if 0 // In case you desperately want the old system back... ;)
static int S_PlayMusic(const char *fn) static int S_PlayMusic(const char *, const char *fn, int loop)
{ {
if (!MusicEnabled()) if (!MusicEnabled())
return 0; return 0;
@ -323,13 +323,9 @@ void S_PauseMusic(bool paused)
} }
#else #else
static int S_PlayMusic(const char* fn, bool looping = true) static int S_PlayMusic(const char *mapname, const char* fn, bool looping = true)
{ {
if (!MusicEnabled()) return Mus_Play(mapname, fn, looping);
return 0;
Mus_Play(fn, looping);
return 1;
} }
void S_StopMusic(void) void S_StopMusic(void)
@ -362,16 +358,11 @@ bool S_TryPlayLevelMusic(unsigned int m)
if (retval < 0) if (retval < 0)
return false; return false;
char const * musicfn = g_mapInfo[m].musicfn; if (!S_PlayMusic(g_mapInfo[m].filename, g_mapInfo[m].musicfn))
if (musicfn != NULL)
{
if (!S_PlayMusic(musicfn))
{ {
S_SetMusicIndex(m); S_SetMusicIndex(m);
return false; return false;
} }
}
return true; return true;
} }
@ -390,7 +381,7 @@ int S_TryPlaySpecialMusic(unsigned int m)
char const * musicfn = g_mapInfo[m].musicfn; char const * musicfn = g_mapInfo[m].musicfn;
if (musicfn != NULL) if (musicfn != NULL)
{ {
if (!S_PlayMusic(musicfn)) if (!S_PlayMusic(nullptr, musicfn))
{ {
S_SetMusicIndex(m); S_SetMusicIndex(m);
return 0; return 0;

View file

@ -166,8 +166,8 @@ void S_MenuSound(void)
S_PlaySound(s); S_PlaySound(s);
} }
#if 0 #if 0 // In case you desperately want the old system back... ;)
static int S_PlayMusic(const char *fn, int loop) static int S_PlayMusic(const char *, const char *fn, int loop)
{ {
if (!MusicEnabled()) if (!MusicEnabled())
return 0; return 0;
@ -288,13 +288,9 @@ void S_PauseMusic(bool paused)
#else #else
static int S_PlayMusic(const char* fn, bool looping) static int S_PlayMusic(const char *mapname, const char* fn, bool looping = true)
{ {
if (!MusicEnabled()) return Mus_Play(mapname, fn, looping);
return 0;
Mus_Play(fn, looping);
return 1;
} }
void S_StopMusic(void) void S_StopMusic(void)
@ -320,18 +316,12 @@ static void S_SetMusicIndex(unsigned int m)
bool S_TryPlayLevelMusic(unsigned int m) bool S_TryPlayLevelMusic(unsigned int m)
{ {
if (RR) // For RR only explicitly invalidate the music name, but still allow the music code to run its own music substitution logic based on map names.
return 1; if (!S_PlayMusic(g_mapInfo[m].filename,RR? nullptr : g_mapInfo[m].musicfn))
char const * musicfn = g_mapInfo[m].musicfn;
if (musicfn != NULL)
{
if (!S_PlayMusic(musicfn, 1))
{ {
S_SetMusicIndex(m); S_SetMusicIndex(m);
return false; return false;
} }
}
return true; return true;
} }
@ -352,7 +342,7 @@ int S_TryPlaySpecialMusic(unsigned int m)
char const * musicfn = g_mapInfo[m].musicfn; char const * musicfn = g_mapInfo[m].musicfn;
if (musicfn != NULL) if (musicfn != NULL)
{ {
if (!S_PlayMusic(musicfn, 1)) if (!S_PlayMusic(nullptr, musicfn, 1))
{ {
S_SetMusicIndex(m); S_SetMusicIndex(m);
return 0; return 0;