- 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 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);
return 0;
}
else
{
// Unable to stat the music.
*gGameOptions.zLevelSong = 0;
}
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);
else
strncpy(buffer, gEpisodeInfo[nEpisode].at28[nLevel].atd0, BMAX_PATH);
bool bReturn = !!sndPlaySong(buffer, true);
if (!bReturn || bSetLevelSong)
bool bReturn = !!sndPlaySong(gEpisodeInfo[nEpisode].at28[nLevel].atd0, buffer, true);
if (bReturn || bSetLevelSong)
strncpy(gGameOptions.zLevelSong, buffer, BMAX_PATH);
else *gGameOptions.zLevelSong = 0;
return bReturn;
}

View file

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

View file

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

View file

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

View file

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

View file

@ -73,6 +73,7 @@ MusPlayingInfo mus_playing;
MusicAliasMap MusicAliases;
MidiDeviceMap MidiDevices;
MusicVolumeMap MusicVolumes;
MusicAliasMap LevelMusicAliases;
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
}
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);
return mus_playing.handle != nullptr;
}
void Mus_Stop()

View file

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

View file

@ -3,6 +3,6 @@
// Totally minimalistic interface - should be all the game modules need.
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_SetPaused(bool on);

View file

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

View file

@ -166,8 +166,8 @@ void S_MenuSound(void)
S_PlaySound(s);
}
#if 0
static int S_PlayMusic(const char *fn, int loop)
#if 0 // In case you desperately want the old system back... ;)
static int S_PlayMusic(const char *, const char *fn, int loop)
{
if (!MusicEnabled())
return 0;
@ -288,13 +288,9 @@ void S_PauseMusic(bool paused)
#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 0;
Mus_Play(fn, looping);
return 1;
return Mus_Play(mapname, fn, looping);
}
void S_StopMusic(void)
@ -320,17 +316,11 @@ static void S_SetMusicIndex(unsigned int m)
bool S_TryPlayLevelMusic(unsigned int m)
{
if (RR)
return 1;
char const * musicfn = g_mapInfo[m].musicfn;
if (musicfn != NULL)
{
if (!S_PlayMusic(musicfn, 1))
{
S_SetMusicIndex(m);
return false;
}
// 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.
if (!S_PlayMusic(g_mapInfo[m].filename,RR? nullptr : g_mapInfo[m].musicfn))
{
S_SetMusicIndex(m);
return false;
}
return true;
@ -352,7 +342,7 @@ int S_TryPlaySpecialMusic(unsigned int m)
char const * musicfn = g_mapInfo[m].musicfn;
if (musicfn != NULL)
{
if (!S_PlayMusic(musicfn, 1))
if (!S_PlayMusic(nullptr, musicfn, 1))
{
S_SetMusicIndex(m);
return 0;