diff --git a/source/core/mapinfo.cpp b/source/core/mapinfo.cpp index 1c4918731..daa4c1627 100644 --- a/source/core/mapinfo.cpp +++ b/source/core/mapinfo.cpp @@ -34,6 +34,7 @@ */ #include "mapinfo.h" +#include "raze_music.h" MapRecord mapList[512]; // Due to how this gets used it needs to be static. EDuke defines 7 episode plus one spare episode with 64 potential levels each and relies on the static array which is freely accessible by scripts. MapRecord *currentLevel; // level that is currently played. (The real level, not what script hacks modfifying the current level index can pretend.) @@ -70,11 +71,11 @@ MapRecord *FindMapByLevelNum(int num) MapRecord *FindNextMap(MapRecord *thismap) { - if (thismap->nextLevel != -1) return mapList[thismap->nextlevel]; + if (thismap->nextLevel != -1) return &mapList[thismap->nextLevel]; return FindMapByLevelNum(thismap->levelNumber+1); } -bool SetMusicForMap(const char* mapname, const char* music, bool namehack = false) +bool SetMusicForMap(const char* mapname, const char* music, bool namehack) { static const char* specials[] = { "intro", "briefing", "loading" }; for (int i = 0; i < 3; i++) @@ -86,10 +87,10 @@ bool SetMusicForMap(const char* mapname, const char* music, bool namehack = fals } } - int index = FindMapByName(mapname); + auto index = FindMapByName(mapname); // This is for the DEFS parser's MUSIC command which never bothered to check for the real map name. - if (index < 0 && namehack) + if (index == nullptr && namehack) { int lev, ep; signed char b1, b2; @@ -102,21 +103,21 @@ bool SetMusicForMap(const char* mapname, const char* music, bool namehack = fals index = FindMapByLevelNum(ep*100 + lev); } - if (index >= 0) + if (index != nullptr) { - mapList[index].music = music; + index->music = music; return true; } return false; } -MapRecord *AlloocateMap() +MapRecord *AllocateMap() { return &mapList[numUsedSlots++]; } -MapRecord* SetupUserMap(const char* boardfilename) +MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic) { for (unsigned i = 0; i < numUsedSlots; i++) { @@ -126,11 +127,11 @@ MapRecord* SetupUserMap(const char* boardfilename) return ↦ } } - auto map = AllocateMap() + auto map = AllocateMap(); map->name = ""; map->SetFileName(boardfilename); map->flags = MI_USERMAP|MI_FORCEEOG; - map->music = G_SetupFilenameBasedMusic(boardfilename, !isRR() ? "dethtoll.mid" : nullptr); + map->music = G_SetupFilenameBasedMusic(boardfilename, defaultmusic); return map; } diff --git a/source/core/mapinfo.h b/source/core/mapinfo.h index 053748f6f..fddf666ec 100644 --- a/source/core/mapinfo.h +++ b/source/core/mapinfo.h @@ -78,6 +78,8 @@ void InitRREndMap(); MapRecord *FindMapByName(const char *nm); MapRecord *FindMapByLevelNum(int num); MapRecord *FindNextMap(MapRecord *thismap); +MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic = nullptr); +MapRecord* AllocateMap(); enum { diff --git a/source/core/savegamehelp.cpp b/source/core/savegamehelp.cpp index 6d036c0c3..17a9114dd 100644 --- a/source/core/savegamehelp.cpp +++ b/source/core/savegamehelp.cpp @@ -305,13 +305,14 @@ int G_ValidateSavegame(FileReader &fr, FString *savetitle, bool formenu) } int savever; - FString engine, gamegrp, mapgrp, title, filename; + FString engine, gamegrp, mapgrp, title, filename, label; arc("Save Version", savever) ("Engine", engine) ("Game Resource", gamegrp) ("Map Resource", mapgrp) ("Title", title) + ("Nap Label", label) ("Map File", filename); auto savesig = gi->GetSaveSig(); @@ -324,25 +325,16 @@ int G_ValidateSavegame(FileReader &fr, FString *savetitle, bool formenu) return 0; } - MapRecord *curLevel = nullptr; + MapRecord *curLevel = FindMapByName(label); - if (strncmp(filename, "file://", 7) != 0) + // If the map does not exist, check if it's a user map. + if (!curLevel) { - for (auto& mr : mapList) - { - if (mr.fileName.Compare(filename) == 0) - { - curLevel = &mr; - } - } - } - else - { - curLevel = &userMapRecord; + curLevel = AllocateMap(); if (!formenu) { - userMapRecord.name = ""; - userMapRecord.SetFileName(filename); + curLevel->name = ""; + curLevel->SetFileName(filename); } } if (!curLevel) return 0; diff --git a/source/duke3d/src/premap.cpp b/source/duke3d/src/premap.cpp index 905b9f194..bceac1052 100644 --- a/source/duke3d/src/premap.cpp +++ b/source/duke3d/src/premap.cpp @@ -1744,7 +1744,6 @@ int G_EnterLevel(int gameMode) auto &p0 = *g_player[0].ps; int16_t playerAngle; - char levelName[BMAX_PATH]; NET_75_CHECK++; // a major problem with how STAT_NETALLOC works, is that loadboard loads sprites directly into the arrays and does not take from // STAT_NETALLOC, even though the loaded sprites are very, very likely to be relevant to the netcode. diff --git a/source/duke3d/src/sounds.cpp b/source/duke3d/src/sounds.cpp index b6476cded..82299ed09 100644 --- a/source/duke3d/src/sounds.cpp +++ b/source/duke3d/src/sounds.cpp @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_EDUKE_NS +extern MapRecord userMapRecord; class DukeSoundEngine : public SoundEngine { diff --git a/source/games/duke/src/2d_r.cpp b/source/games/duke/src/2d_r.cpp index 09320505a..aff2a3f71 100644 --- a/source/games/duke/src/2d_r.cpp +++ b/source/games/duke/src/2d_r.cpp @@ -600,7 +600,6 @@ void dobonus_r(bool bonusonly, CompletionFunc completion) class DRRLoadScreen : public DScreenJob { - std::function<int(void)> callback; std::function<int(void)> callback; MapRecord* rec; diff --git a/source/games/duke/src/actors_r.cpp b/source/games/duke/src/actors_r.cpp index c784dafb3..36ba591f2 100644 --- a/source/games/duke/src/actors_r.cpp +++ b/source/games/duke/src/actors_r.cpp @@ -2139,7 +2139,7 @@ static void rrra_specialstats() { ps[screenpeek].gm = MODE_EOL; ud.eog = 1; - ud.nextLevel = FindNextMap(currentLevel); + ud.nextLevel = nullptr; } } diff --git a/source/games/duke/src/ccmds.cpp b/source/games/duke/src/ccmds.cpp index 0e8fac9e6..c084c2991 100644 --- a/source/games/duke/src/ccmds.cpp +++ b/source/games/duke/src/ccmds.cpp @@ -43,7 +43,7 @@ bool cheatStuff(cheatseq_t* s); bool cheatKeys(cheatseq_t* s); bool cheatInventory(cheatseq_t* s); -static void dowarp(int volume, int level) +static void dowarp(MapRecord *map) { ud.m_monsters_off = ud.monsters_off = 0; @@ -54,10 +54,10 @@ static void dowarp(int volume, int level) if (ps[myconnectindex].gm & MODE_GAME) { - G_NewGame(volume, level, ud.m_player_skill); + G_NewGame(map, ud.m_player_skill); ps[myconnectindex].gm = MODE_RESTART; } - else G_NewGame_EnterLevel(volume, level, ud.m_player_skill); + else G_NewGame_EnterLevel(map, ud.m_player_skill); } static int ccmd_levelwarp(CCmdFuncPtr parm) @@ -71,7 +71,13 @@ static int ccmd_levelwarp(CCmdFuncPtr parm) Printf(TEXTCOLOR_RED "Invalid level!: E%sL%s\n", parm->parms[0], parm->parms[1]); return CCMD_OK; } - dowarp(e - 1, m - 1); + auto map = FindMapByLevelNum(levelnum(e - 1, m - 1)); + if (!map) + { + Printf(TEXTCOLOR_RED "Level not found!: E%sL%s\n", parm->parms[0], parm->parms[1]); + return CCMD_OK; + } + dowarp(map); return CCMD_OK; } @@ -89,36 +95,26 @@ static int ccmd_map(CCmdFuncPtr parm) Printf(TEXTCOLOR_RED "map: file \"%s\" not found.\n", mapname.GetChars()); return CCMD_OK; } - int volume, level; // Check if the map is already defined. - for (int i = 0; i < 512; i++) + auto map = FindMapByName(mapname); + if (map == nullptr) { - if (mapList[i].labelName.CompareNoCase(mapname) == 0) + // got a user map + if (VOLUMEONE) { - volume = i / MAXLEVELS; - level = i % MAXLEVELS; - goto foundone; + Printf(TEXTCOLOR_RED "Cannot use user maps in shareware.\n"); + return CCMD_OK; } + DefaultExtension(mapname, ".map"); + if (mapname[0] != '/') mapname.Insert(0, "/"); + map = SetupUserMap(mapname, !isRR() ? "dethtoll.mid" : nullptr); } - if (VOLUMEONE) - { - Printf(TEXTCOLOR_RED "Cannot use user maps in shareware.\n"); - return CCMD_OK; - } - // Treat as user map if not found in the list of regular maps. - boardfilename[0] = '/'; - boardfilename[1] = 0; - volume = 0; - level = 7; - DefaultExtension(mapname, ".map"); - strcat(boardfilename, mapname); -foundone: if (numplayers > 1) { return CCMD_OK; } - dowarp(volume, level); + dowarp(map); return CCMD_OK; } diff --git a/source/games/duke/src/cheats.cpp b/source/games/duke/src/cheats.cpp index 5c07ef519..9440f7ccf 100644 --- a/source/games/duke/src/cheats.cpp +++ b/source/games/duke/src/cheats.cpp @@ -179,8 +179,10 @@ static bool cheatLevel(cheatseq_t *s) levnume = (s->Args[1] - '0')*10+(s->Args[2]-'0') - 1; // Instead of hard coded range checks on volume and level, let's just check if the level is defined. - if (mapList[volnume*MAXLEVELS + levnume].fileName.IsNotEmpty()) + auto map = FindMapByLevelNum(levelnum(volnume, levnume)); + if (map) { + ud.nextLevel = map; FX_StopAllSounds(); FX_SetReverb(0); ps[myconnectindex].gm |= MODE_RESTART; diff --git a/source/games/duke/src/d_menu.cpp b/source/games/duke/src/d_menu.cpp index afecb8c98..fa7e701e4 100644 --- a/source/games/duke/src/d_menu.cpp +++ b/source/games/duke/src/d_menu.cpp @@ -40,6 +40,7 @@ Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms #include "gstrings.h" #include "version.h" #include "names.h" +#include "mapinfo.h" #include "../../glbackend/glbackend.h" @@ -317,7 +318,11 @@ void GameInterface::StartGame(FNewGameStartup& gs) ud.m_respawn_items = 0; ud.m_respawn_inventory = 0; ud.multimode = 1; - G_NewGame_EnterLevel(gs.Episode, gs.Level, ud.m_player_skill); + auto map = FindMapByLevelNum(levelnum(gs.Episode, gs.Level)); + if (map) + { + G_NewGame_EnterLevel(map, ud.m_player_skill); + } } diff --git a/source/games/duke/src/funct.h b/source/games/duke/src/funct.h index 656983f05..65529c92c 100644 --- a/source/games/duke/src/funct.h +++ b/source/games/duke/src/funct.h @@ -220,5 +220,6 @@ void prelevel_d(int g); void prelevel_r(int g); void e4intro(CompletionFunc completion); void clearfrags(void); +int exitlevel(); END_DUKE_NS diff --git a/source/games/duke/src/game.h b/source/games/duke/src/game.h index 94f0a4ac1..2404d2969 100644 --- a/source/games/duke/src/game.h +++ b/source/games/duke/src/game.h @@ -45,8 +45,6 @@ extern int rtsplaying; #ifndef ONLY_USERDEFS extern char boardfilename[BMAX_PATH]; -#define USERMAPMUSICFAKEVOLUME MAXVOLUMES -#define USERMAPMUSICFAKELEVEL (MAXLEVELS-1) extern int32_t g_Shareware; extern int32_t cameraclock; @@ -90,11 +88,11 @@ static inline int32_t calc_smoothratio(ClockTicks totalclk, ClockTicks ototalclk } -static inline void G_NewGame_EnterLevel(int volume, int level, int skill) +static inline void G_NewGame_EnterLevel(MapRecord *map, int skill) { - G_NewGame(volume, level, skill); + G_NewGame(map, skill); - if (G_EnterLevel(MODE_GAME)) + if (enterlevel(map, MODE_GAME)) G_BackToMenu(); } diff --git a/source/games/duke/src/gamedef.cpp b/source/games/duke/src/gamedef.cpp index 6c067dfda..a8c07dd8f 100644 --- a/source/games/duke/src/gamedef.cpp +++ b/source/games/duke/src/gamedef.cpp @@ -42,6 +42,7 @@ into many sub-files. #include "menu.h" #include "global.h" #include "m_argv.h" +#include "sounds.h" BEGIN_DUKE_NS @@ -63,6 +64,16 @@ extern int* labelcode; TArray<int> ScriptCode; +struct TempMusic +{ + int levnum; + FString music; +}; + +// This is for situations where the music gets defined before the map. Since the map records do not exist yet, we need a temporary buffer. +static TArray<TempMusic> tempMusic; + + //--------------------------------------------------------------------------- // // synthesize the instruction list @@ -752,35 +763,40 @@ int parsecommand() popscriptvalue(); transnum(); // Volume Number (0/4) k = popscriptvalue() - 1; + if (k < 0) specialmusic.Clear(); - if (k == -1) k = MAXVOLUMES; - - if (k >= 0) // if it's background music + i = 0; + // get the file name... + while (keyword() == -1) { - i = 0; - // get the file name... - while (keyword() == -1) + while (isaltok(*textptr) == 0) { - while (isaltok(*textptr) == 0) - { - if (*textptr == 0x0a) line_number++; - textptr++; - if (*textptr == 0) break; - } - j = 0; - parsebuffer.Clear(); - while (isaltok(*(textptr + j))) - { - parsebuffer.Push(textptr[j]); - j++; - } - parsebuffer.Push(0); - mapList[(MAXLEVELS * k) + i].music = parsebuffer.Data(); - textptr += j; - if (i > MAXLEVELS) break; - i++; + if (*textptr == 0x0a) line_number++; + textptr++; + if (*textptr == 0) break; } + j = 0; + parsebuffer.Clear(); + while (isaltok(*(textptr + j))) + { + parsebuffer.Push(textptr[j]); + j++; + } + parsebuffer.Push(0); + if (k >= 0) + { + tempMusic.Reserve(1); + tempMusic.Last().levnum = levelnum(k, i); + tempMusic.Last().music = parsebuffer.Data(); + textptr += j; + } + else + { + specialmusic.Push(parsebuffer.Data()); + } + i++; } + return 0; } case concmd_include: @@ -1395,6 +1411,7 @@ int parsecommand() return 0; case concmd_definelevelname: + { popscriptvalue(); transnum(); j = popscriptvalue(); @@ -1410,22 +1427,25 @@ int parsecommand() textptr++, i++; } parsebuffer.Push(0); - mapList[j * MAXLEVELS + k].SetFileName(parsebuffer.Data()); + auto levnum = levelnum(j, k); + auto map = FindMapByLevelNum(levnum); + if (!map) map = AllocateMap(); + map->SetFileName(parsebuffer.Data()); while (*textptr == ' ') textptr++; - mapList[j * MAXLEVELS + k].parTime = + map->parTime = (((*(textptr + 0) - '0') * 10 + (*(textptr + 1) - '0')) * 26 * 60) + (((*(textptr + 3) - '0') * 10 + (*(textptr + 4) - '0')) * 26); textptr += 5; while (*textptr == ' ') textptr++; - mapList[j * MAXLEVELS + k].designerTime = + map->designerTime = (((*(textptr + 0) - '0') * 10 + (*(textptr + 1) - '0')) * 26 * 60) + (((*(textptr + 3) - '0') * 10 + (*(textptr + 4) - '0')) * 26); - mapList[j * MAXLEVELS + k].levelNumber = k + j * 100; + map->levelNumber = levnum; textptr += 5; while (*textptr == ' ') textptr++; @@ -1439,9 +1459,9 @@ int parsecommand() textptr++, i++; } parsebuffer.Push(0); - mapList[j * MAXLEVELS + k].name = parsebuffer.Data(); + map->name = parsebuffer.Data(); return 0; - + } case concmd_definequote: popscriptvalue(); transnum(); @@ -1703,6 +1723,12 @@ void loadcons(const char* filenam) // These can only be retrieved AFTER loading the scripts. InitGameVarPointers(); ResetSystemDefaults(); + for (auto& tm : tempMusic) + { + auto map = FindMapByLevelNum(tm.levnum); + if (map) map->music = tm.music; + } + tempMusic.Clear(); } diff --git a/source/games/duke/src/gamevar.cpp b/source/games/duke/src/gamevar.cpp index 44db1e8a8..6d73e446a 100644 --- a/source/games/duke/src/gamevar.cpp +++ b/source/games/duke/src/gamevar.cpp @@ -560,6 +560,7 @@ void InitGameVarPointers(void) // //--------------------------------------------------------------------------- +// These are deliberately not stored in accessible variables anymore int getmap() { return mapfromlevelnum(currentLevel->levelNumber); } int getvol() { return volfromlevelnum(currentLevel->levelNumber); } diff --git a/source/games/duke/src/global.h b/source/games/duke/src/global.h index 0a18fc851..ac5299b49 100644 --- a/source/games/duke/src/global.h +++ b/source/games/duke/src/global.h @@ -40,15 +40,12 @@ BEGIN_DUKE_NS #define MOVEFIFOSIZ 256 -#define MAXLEVELS 64 #define MAXGAMETYPES 16 enum { - MUS_FIRST_SPECIAL = MAXVOLUMES * MAXLEVELS, - - MUS_INTRO = MUS_FIRST_SPECIAL, - MUS_BRIEFING = MUS_FIRST_SPECIAL + 1, - MUS_LOADING = MUS_FIRST_SPECIAL + 2, + MUS_INTRO = 0, + MUS_BRIEFING = 1, + MUS_LOADING = 2, }; @@ -127,8 +124,7 @@ G_EXTERN int32_t g_earthquakeTime; G_EXTERN int32_t g_freezerSelfDamage; #define freezerhurtowner g_freezerSelfDamage G_EXTERN int32_t g_gameQuit; -G_EXTERN int32_t g_globalRandom; -#define global_random g_globalRandom +G_EXTERN int32_t global_random; G_EXTERN int32_t impact_damage; extern int32_t labelcnt; G_EXTERN int32_t g_maxPlayerHealth; @@ -220,7 +216,7 @@ G_EXTERN int16_t fakebubba_spawn, mamaspawn_count, banjosound, g_bellTime, BellS #define BellTime g_bellTime #define word_119BE0 BellSprite G_EXTERN uint8_t g_spriteExtra[MAXSPRITES], g_sectorExtra[MAXSECTORS]; // move these back into the base structs! -G_EXTERN uint8_t enemysizecheat, ufospawnsminion, pistonsound, chickenphase, RRRA_ExitedLevel, RRRA_EndEpisode, fogactive; +G_EXTERN uint8_t enemysizecheat, ufospawnsminion, pistonsound, chickenphase, RRRA_ExitedLevel, fogactive; G_EXTERN int32_t g_cdTrack; #define raat607 enemysizecheat // only as a reminder #define raat605 chickenphase @@ -241,7 +237,6 @@ G_EXTERN player_orig po[MAXPLAYERS]; #pragma pack(pop) G_EXTERN uint32_t everyothertime; -G_EXTERN uint32_t g_moveThingsCount; G_EXTERN double g_gameUpdateTime; G_EXTERN double g_gameUpdateAndDrawTime; #define GAMEUPDATEAVGTIMENUMSAMPLES 100 diff --git a/source/games/duke/src/premap.cpp b/source/games/duke/src/premap.cpp index 1007127b4..fe79f5edf 100644 --- a/source/games/duke/src/premap.cpp +++ b/source/games/duke/src/premap.cpp @@ -908,17 +908,6 @@ int enterlevel(MapRecord *mi, int gamemode) return 0; } -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - -void setmapfog(int fogtype) -{ - GLInterface.SetMapFog(fogtype != 0); -} - //--------------------------------------------------------------------------- // // Ideally this will become the only place where map progression gets set up. @@ -964,4 +953,58 @@ bool setnextmap(bool checksecretexit) return false; } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +int exitlevel(void) +{ + bool endofgame = ud.eog || (currentLevel->flags & MI_FORCEEOG) || ud.nextLevel == nullptr; + STAT_Update(endofgame); + setpal(&ps[myconnectindex]); + + if (ps[myconnectindex].gm & MODE_RESTART) + { + ud.nextLevel = currentLevel; + } + + if (ps[myconnectindex].gm & MODE_EOL) + { + ready2send = 0; + dobonus(0); + + // Clear potentially loaded per-map ART only after the bonus screens. + artClearMapArt(); + + if (endofgame) + { + ud.eog = 0; + if (ud.multimode < 2) + { + if (!VOLUMEALL) + doorders([](bool) {}); + ps[myconnectindex].gm = 0; + return 2; + } + else + { + ud.nextLevel = FindMapByLevelNum(0); + if (!ud.nextLevel) return 2; + } + } + } + + ready2send = 0; + + if (numplayers > 1) + ps[myconnectindex].gm = MODE_GAME; + + int res = enterlevel(ud.nextLevel, ps[myconnectindex].gm); + ud.nextLevel = nullptr; + return res ? 2 : 1; +} + + END_DUKE_NS \ No newline at end of file diff --git a/source/games/duke/src/premap.h b/source/games/duke/src/premap.h index 7b9bb5947..11b937610 100644 --- a/source/games/duke/src/premap.h +++ b/source/games/duke/src/premap.h @@ -29,10 +29,8 @@ BEGIN_DUKE_NS extern int16_t ambientlotag[64]; extern int16_t ambienthitag[64]; -int G_EnterLevel(MapRecord *mi, int gameMode); -int G_FindLevelByFile(const char *fileName); -void G_NewGame(int volumeNum, int levelNum, int skillNum); -void G_ResetTimers(uint8_t keepgtics); +int enterlevel(MapRecord *mi, int gameMode); +void G_NewGame(MapRecord *mi, int skillNum); void P_ResetPlayer(int pn); void G_ResetInterpolations(void); void G_InitRRRASkies(void); diff --git a/source/games/duke/src/sounds.cpp b/source/games/duke/src/sounds.cpp index b954deda2..b880d82fb 100644 --- a/source/games/duke/src/sounds.cpp +++ b/source/games/duke/src/sounds.cpp @@ -44,35 +44,37 @@ source as it is released. BEGIN_DUKE_NS +TArray<FString> specialmusic; + class DukeSoundEngine : public SoundEngine { - // client specific parts of the sound engine go in this class. - void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan) override; - TArray<uint8_t> ReadSound(int lumpnum) override; + // client specific parts of the sound engine go in this class. + void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan) override; + TArray<uint8_t> ReadSound(int lumpnum) override; public: - DukeSoundEngine() - { - S_Rolloff.RolloffType = ROLLOFF_Doom; // Seems like Duke uses the same rolloff type as Doom. - S_Rolloff.MinDistance = 144; // was originally 576 which looks like a bug and sounds like crap. - S_Rolloff.MaxDistance = 1088; - } + DukeSoundEngine() + { + S_Rolloff.RolloffType = ROLLOFF_Doom; // Seems like Duke uses the same rolloff type as Doom. + S_Rolloff.MinDistance = 144; // was originally 576 which looks like a bug and sounds like crap. + S_Rolloff.MaxDistance = 1088; + } - void StopChannel(FSoundChan* chan) override - { - if (chan && chan->SysChannel != NULL && !(chan->ChanFlags & CHANF_EVICTED) && chan->SourceType == SOURCE_Actor) - { - chan->Source = NULL; - chan->SourceType = SOURCE_Unattached; - } - SoundEngine::StopChannel(chan); - } + void StopChannel(FSoundChan* chan) override + { + if (chan && chan->SysChannel != NULL && !(chan->ChanFlags & CHANF_EVICTED) && chan->SourceType == SOURCE_Actor) + { + chan->Source = NULL; + chan->SourceType = SOURCE_Unattached; + } + SoundEngine::StopChannel(chan); + } }; void S_InitSound() { - soundEngine = new DukeSoundEngine; + soundEngine = new DukeSoundEngine; } //========================================================================== @@ -83,8 +85,8 @@ void S_InitSound() TArray<uint8_t> DukeSoundEngine::ReadSound(int lumpnum) { - auto wlump = fileSystem.OpenFileReader(lumpnum); - return wlump.Read(); + auto wlump = fileSystem.OpenFileReader(lumpnum); + return wlump.Read(); } //========================================================================== @@ -95,7 +97,7 @@ TArray<uint8_t> DukeSoundEngine::ReadSound(int lumpnum) void S_PauseSounds(bool paused) { - soundEngine->SetPaused(paused); + soundEngine->SetPaused(paused); } //========================================================================== @@ -106,14 +108,14 @@ void S_PauseSounds(bool paused) void cacheAllSounds(void) { - auto& sfx = soundEngine->GetSounds(); - int i = 0; - for(auto &snd : sfx) - { - soundEngine->CacheSound(&snd); - if (((++i)&31) == 0) - handleevents(); - } + auto& sfx = soundEngine->GetSounds(); + int i = 0; + for(auto &snd : sfx) + { + soundEngine->CacheSound(&snd); + if (((++i)&31) == 0) + handleevents(); + } } //========================================================================== @@ -124,23 +126,23 @@ void cacheAllSounds(void) static inline int S_GetPitch(int num) { - auto const* snd = soundEngine->GetUserData(num+1); - if (!snd) return 0; - int const range = abs(snd[kPitchEnd] - snd[kPitchStart]); - return (range == 0) ? snd[kPitchStart] : min(snd[kPitchStart], snd[kPitchEnd]) + rand() % range; + auto const* snd = soundEngine->GetUserData(num+1); + if (!snd) return 0; + int const range = abs(snd[kPitchEnd] - snd[kPitchStart]); + return (range == 0) ? snd[kPitchStart] : min(snd[kPitchStart], snd[kPitchEnd]) + rand() % range; } float S_ConvertPitch(int lpitch) { - return pow(2, lpitch / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave. + return pow(2, lpitch / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave. } int S_GetUserFlags(int num) { - if (!soundEngine->isValidSoundId(num+1)) return 0; - auto const* snd = soundEngine->GetUserData(num + 1); - if (!snd) return 0; - return snd[kFlags]; + if (!soundEngine->isValidSoundId(num+1)) return 0; + auto const* snd = soundEngine->GetUserData(num + 1); + if (!snd) return 0; + return snd[kFlags]; } //========================================================================== @@ -151,41 +153,41 @@ int S_GetUserFlags(int num) int S_DefineSound(unsigned index, const char *filename, int minpitch, int maxpitch, int priority, int type, int distance, float volume) { - auto& S_sfx = soundEngine->GetSounds(); - index++; - unsigned oldindex = S_sfx.Size(); - if (index >= S_sfx.Size()) - { - S_sfx.Resize(index + 1); - for (; oldindex <= index; oldindex++) - { - S_sfx[oldindex].Clear(); - } - } - auto sfx = &S_sfx[index]; - bool alreadydefined = !sfx->bTentative; - sfx->UserData.Resize(kMaxUserData); - auto sndinf = sfx->UserData.Data(); - sndinf[kFlags] = type & ~SF_ONEINST_INTERNAL; - if (sndinf[kFlags] & SF_LOOP) - sndinf[kFlags] |= SF_ONEINST_INTERNAL; + auto& S_sfx = soundEngine->GetSounds(); + index++; + unsigned oldindex = S_sfx.Size(); + if (index >= S_sfx.Size()) + { + S_sfx.Resize(index + 1); + for (; oldindex <= index; oldindex++) + { + S_sfx[oldindex].Clear(); + } + } + auto sfx = &S_sfx[index]; + bool alreadydefined = !sfx->bTentative; + sfx->UserData.Resize(kMaxUserData); + auto sndinf = sfx->UserData.Data(); + sndinf[kFlags] = type & ~SF_ONEINST_INTERNAL; + if (sndinf[kFlags] & SF_LOOP) + sndinf[kFlags] |= SF_ONEINST_INTERNAL; - sfx->lumpnum = S_LookupSound(filename); - sndinf[kPitchStart] = clamp(minpitch, INT16_MIN, INT16_MAX); - sndinf[kPitchEnd] = clamp(maxpitch, INT16_MIN, INT16_MAX); - sndinf[kPriority] = priority & 255; - sndinf[kVolAdjust] = clamp(distance, INT16_MIN, INT16_MAX); - sfx->Volume = volume; - sfx->NearLimit = 6; - sfx->bTentative = false; - sfx->name = filename; - return 0; + sfx->lumpnum = S_LookupSound(filename); + sndinf[kPitchStart] = clamp(minpitch, INT16_MIN, INT16_MAX); + sndinf[kPitchEnd] = clamp(maxpitch, INT16_MIN, INT16_MAX); + sndinf[kPriority] = priority & 255; + sndinf[kVolAdjust] = clamp(distance, INT16_MIN, INT16_MAX); + sfx->Volume = volume; + sfx->NearLimit = 6; + sfx->bTentative = false; + sfx->name = filename; + return 0; } inline bool S_IsAmbientSFX(int spriteNum) { - return (sprite[spriteNum].picnum == MUSICANDSFX && sprite[spriteNum].lotag < 999); + return (sprite[spriteNum].picnum == MUSICANDSFX && sprite[spriteNum].lotag < 999); } //========================================================================== @@ -195,56 +197,56 @@ inline bool S_IsAmbientSFX(int spriteNum) //========================================================================== static int GetPositionInfo(int spriteNum, int soundNum, int sectNum, - const vec3_t *cam, const vec3_t *pos, int *distPtr, FVector3 *sndPos) + const vec3_t *cam, const vec3_t *pos, int *distPtr, FVector3 *sndPos) { - // There's a lot of hackery going on here that could be mapped to rolloff and attenuation parameters. - // However, ultimately rolloff would also just reposition the sound source so this can remain as it is. + // There's a lot of hackery going on here that could be mapped to rolloff and attenuation parameters. + // However, ultimately rolloff would also just reposition the sound source so this can remain as it is. - auto sp = &sprite[spriteNum]; - int orgsndist = 0, sndang = 0, sndist = 0, explosion = 0; - auto const* snd = soundEngine->GetUserData(soundNum + 1); - int userflags = snd ? snd[kFlags] : 0; - int dist_adjust = snd ? snd[kVolAdjust] : 0; + auto sp = &sprite[spriteNum]; + int orgsndist = 0, sndang = 0, sndist = 0, explosion = 0; + auto const* snd = soundEngine->GetUserData(soundNum + 1); + int userflags = snd ? snd[kFlags] : 0; + int dist_adjust = snd ? snd[kVolAdjust] : 0; - if (sp->picnum != TILE_APLAYER || sp->yvel != screenpeek) - { - orgsndist = sndist = FindDistance3D(cam->x - pos->x, cam->y - pos->y, (cam->z - pos->z)); + if (sp->picnum != TILE_APLAYER || sp->yvel != screenpeek) + { + orgsndist = sndist = FindDistance3D(cam->x - pos->x, cam->y - pos->y, (cam->z - pos->z)); - if ((userflags & (SF_GLOBAL | SF_DTAG)) != SF_GLOBAL && sp->picnum == MUSICANDSFX && sp->lotag < 999 && (sector[sp->sectnum].lotag & 0xff) < ST_9_SLIDING_ST_DOOR) - sndist = divscale14(sndist, sp->hitag + 1); - } + if ((userflags & (SF_GLOBAL | SF_DTAG)) != SF_GLOBAL && sp->picnum == MUSICANDSFX && sp->lotag < 999 && (sector[sp->sectnum].lotag & 0xff) < ST_9_SLIDING_ST_DOOR) + sndist = divscale14(sndist, sp->hitag + 1); + } - sndist += dist_adjust; - if (sndist < 0) sndist = 0; + sndist += dist_adjust; + if (sndist < 0) sndist = 0; - if (sectNum > -1 && sndist && sp->picnum != MUSICANDSFX && !cansee(cam->x, cam->y, cam->z - (24 << 8), sectNum, sp->x, sp->y, sp->z - (24 << 8), sp->sectnum)) - sndist += sndist >> (isRR() ? 2 : 5); + if (sectNum > -1 && sndist && sp->picnum != MUSICANDSFX && !cansee(cam->x, cam->y, cam->z - (24 << 8), sectNum, sp->x, sp->y, sp->z - (24 << 8), sp->sectnum)) + sndist += sndist >> (isRR() ? 2 : 5); - // Here the sound distance was clamped to a minimum of 144*4. - // It's better to handle rolloff in the backend instead of whacking the sound origin here. - // That way the lower end can be made customizable instead of losing all precision right here at the source. - if (sndist < 0) sndist = 0; + // Here the sound distance was clamped to a minimum of 144*4. + // It's better to handle rolloff in the backend instead of whacking the sound origin here. + // That way the lower end can be made customizable instead of losing all precision right here at the source. + if (sndist < 0) sndist = 0; - if (distPtr) - { - *distPtr = sndist; - } + if (distPtr) + { + *distPtr = sndist; + } - if (sndPos) - { - FVector3 sndorg = GetSoundPos(pos); - FVector3 campos = GetSoundPos(cam); - // Now calculate the virtual position in sound system coordinates. - FVector3 sndvec = sndorg - campos; - if (orgsndist > 0) - { - float scale = float(sndist) / orgsndist; // adjust by what was calculated above; - *sndPos = campos + sndvec * scale; - } - else *sndPos = campos; - } + if (sndPos) + { + FVector3 sndorg = GetSoundPos(pos); + FVector3 campos = GetSoundPos(cam); + // Now calculate the virtual position in sound system coordinates. + FVector3 sndvec = sndorg - campos; + if (orgsndist > 0) + { + float scale = float(sndist) / orgsndist; // adjust by what was calculated above; + *sndPos = campos + sndvec * scale; + } + else *sndPos = campos; + } - return false; + return false; } //========================================================================== @@ -255,19 +257,19 @@ static int GetPositionInfo(int spriteNum, int soundNum, int sectNum, void S_GetCamera(vec3_t** c, int32_t* ca, int32_t* cs) { - if (ud.camerasprite == -1) - { - auto p = &ps[screenpeek]; - if (c) *c = &p->pos; - if (cs) *cs = p->cursectnum; - if (ca) *ca = p->getang(); - } - else - { - if (c) *c = &sprite[ud.camerasprite].pos; - if (cs) *cs = sprite[ud.camerasprite].sectnum; - if (ca) *ca = sprite[ud.camerasprite].ang; - } + if (ud.camerasprite == -1) + { + auto p = &ps[screenpeek]; + if (c) *c = &p->pos; + if (cs) *cs = p->cursectnum; + if (ca) *ca = p->getang(); + } + else + { + if (c) *c = &sprite[ud.camerasprite].pos; + if (cs) *cs = sprite[ud.camerasprite].sectnum; + if (ca) *ca = sprite[ud.camerasprite].ang; + } } //========================================================================= @@ -280,42 +282,42 @@ void S_GetCamera(vec3_t** c, int32_t* ca, int32_t* cs) void DukeSoundEngine::CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan) { - if (pos != nullptr) - { - vec3_t* campos; - int32_t camsect; + if (pos != nullptr) + { + vec3_t* campos; + int32_t camsect; - S_GetCamera(&campos, nullptr, &camsect); - if (vel) vel->Zero(); + S_GetCamera(&campos, nullptr, &camsect); + if (vel) vel->Zero(); - if (type == SOURCE_Unattached) - { - pos->X = pt[0]; - pos->Y = pt[1]; - pos->Z = pt[2]; - } - else if (type == SOURCE_Actor) - { - auto actor = (spritetype*)source; - assert(actor != nullptr); - if (actor != nullptr) - { - GetPositionInfo(int(actor - sprite), chanSound - 1, camsect, campos, &actor->pos, nullptr, pos); - /* - if (vel) // DN3D does not properly maintain this. - { - vel->X = float(actor->Vel.X * TICRATE); - vel->Y = float(actor->Vel.Z * TICRATE); - vel->Z = float(actor->Vel.Y * TICRATE); - } - */ - } - } - if ((chanflags & CHANF_LISTENERZ) && campos != nullptr && type != SOURCE_None) - { - pos->Y = campos->z / 256.f; - } - } + if (type == SOURCE_Unattached) + { + pos->X = pt[0]; + pos->Y = pt[1]; + pos->Z = pt[2]; + } + else if (type == SOURCE_Actor) + { + auto actor = (spritetype*)source; + assert(actor != nullptr); + if (actor != nullptr) + { + GetPositionInfo(int(actor - sprite), chanSound - 1, camsect, campos, &actor->pos, nullptr, pos); + /* + if (vel) // DN3D does not properly maintain this. + { + vel->X = float(actor->Vel.X * TICRATE); + vel->Y = float(actor->Vel.Z * TICRATE); + vel->Z = float(actor->Vel.Y * TICRATE); + } + */ + } + } + if ((chanflags & CHANF_LISTENERZ) && campos != nullptr && type != SOURCE_None) + { + pos->Y = campos->z / 256.f; + } + } } @@ -327,40 +329,40 @@ void DukeSoundEngine::CalcPosVel(int type, const void* source, const float pt[3] void S_Update(void) { - SoundListener listener; - vec3_t* c; - int32_t ca, cs; + SoundListener listener; + vec3_t* c; + int32_t ca, cs; - auto& gm = g_player[myconnectindex].ps->gm; - if (isRR() && !Mus_IsPlaying() && (gm && gm & MODE_GAME)) - S_PlayRRMusic(); + auto& gm = g_player[myconnectindex].ps->gm; + if (isRR() && !Mus_IsPlaying() && (gm && gm & MODE_GAME)) + S_PlayRRMusic(); - S_GetCamera(&c, &ca, &cs); + S_GetCamera(&c, &ca, &cs); - if (c != nullptr) - { - listener.angle = -(float)ca * pi::pi() / 1024; // Build uses a period of 2048. - listener.velocity.Zero(); - listener.position = GetSoundPos(c); - listener.underwater = false; - // This should probably use a real environment instead of the pitch hacking in S_PlaySound3D. - // listenactor->waterlevel == 3; - //assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber); - listener.Environment = 0;// primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment; - listener.valid = true; - } - else - { - listener.angle = 0; - listener.position.Zero(); - listener.velocity.Zero(); - listener.underwater = false; - listener.Environment = nullptr; - listener.valid = false; - } - listener.ListenerObject = ud.camerasprite == -1 ? nullptr : &sprite[ud.camerasprite]; - soundEngine->SetListener(listener); - soundEngine->UpdateSounds((int)totalclock); + if (c != nullptr) + { + listener.angle = -(float)ca * pi::pi() / 1024; // Build uses a period of 2048. + listener.velocity.Zero(); + listener.position = GetSoundPos(c); + listener.underwater = false; + // This should probably use a real environment instead of the pitch hacking in S_PlaySound3D. + // listenactor->waterlevel == 3; + //assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber); + listener.Environment = 0;// primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment; + listener.valid = true; + } + else + { + listener.angle = 0; + listener.position.Zero(); + listener.velocity.Zero(); + listener.underwater = false; + listener.Environment = nullptr; + listener.valid = false; + } + listener.ListenerObject = ud.camerasprite == -1 ? nullptr : &sprite[ud.camerasprite]; + soundEngine->SetListener(listener); + soundEngine->UpdateSounds((int)totalclock); } @@ -372,81 +374,81 @@ void S_Update(void) int S_PlaySound3D(int sndnum, int spriteNum, const vec3_t* pos, int channel, EChanFlags flags) { - auto const pl = &ps[myconnectindex]; - if (!soundEngine->isValidSoundId(sndnum+1) || !SoundEnabled() || (unsigned)spriteNum >= MAXSPRITES || (pl->gm & MODE_MENU) || - (pl->timebeforeexit > 0 && pl->timebeforeexit <= REALGAMETICSPERSEC * 3)) return -1; + auto const pl = &ps[myconnectindex]; + if (!soundEngine->isValidSoundId(sndnum+1) || !SoundEnabled() || (unsigned)spriteNum >= MAXSPRITES || (pl->gm & MODE_MENU) || + (pl->timebeforeexit > 0 && pl->timebeforeexit <= REALGAMETICSPERSEC * 3)) return -1; - int userflags = S_GetUserFlags(sndnum); + int userflags = S_GetUserFlags(sndnum); - auto sp = &sprite[spriteNum]; + auto sp = &sprite[spriteNum]; - if ((userflags & (SF_DTAG | SF_GLOBAL)) == SF_DTAG) - { - // Duke-Tag sound does not play in 3D. - return S_PlaySound(sndnum); - } + if ((userflags & (SF_DTAG | SF_GLOBAL)) == SF_DTAG) + { + // Duke-Tag sound does not play in 3D. + return S_PlaySound(sndnum); + } - if (userflags & SF_TALK) - { - if (snd_speech == 0 || (ud.multimode > 1 && sp->picnum == TILE_APLAYER && sp->yvel != screenpeek && ud.coop != 1)) return -1; - bool foundone = soundEngine->EnumerateChannels([&](FSoundChan* chan) - { - auto sid = chan->OrgID; - auto flags = S_GetUserFlags(sid - 1); - return !!(flags & SF_TALK); - }); - // don't play if any Duke talk sounds are already playing - if (foundone) return -1; - } + if (userflags & SF_TALK) + { + if (snd_speech == 0 || (ud.multimode > 1 && sp->picnum == TILE_APLAYER && sp->yvel != screenpeek && ud.coop != 1)) return -1; + bool foundone = soundEngine->EnumerateChannels([&](FSoundChan* chan) + { + auto sid = chan->OrgID; + auto flags = S_GetUserFlags(sid - 1); + return !!(flags & SF_TALK); + }); + // don't play if any Duke talk sounds are already playing + if (foundone) return -1; + } - int32_t sndist; - FVector3 sndpos; // this is in sound engine space. + int32_t sndist; + FVector3 sndpos; // this is in sound engine space. - vec3_t* campos; - int32_t camsect; + vec3_t* campos; + int32_t camsect; - S_GetCamera(&campos, nullptr, &camsect); - GetPositionInfo(spriteNum, sndnum, camsect, campos, pos, &sndist, &sndpos); - int pitch = S_GetPitch(sndnum); + S_GetCamera(&campos, nullptr, &camsect); + GetPositionInfo(spriteNum, sndnum, camsect, campos, pos, &sndist, &sndpos); + int pitch = S_GetPitch(sndnum); - bool explosion = ((userflags & (SF_GLOBAL | SF_DTAG)) == (SF_GLOBAL | SF_DTAG)) || ((sndnum == PIPEBOMB_EXPLODE || sndnum == LASERTRIP_EXPLODE || sndnum == RPG_EXPLODE)); + bool explosion = ((userflags & (SF_GLOBAL | SF_DTAG)) == (SF_GLOBAL | SF_DTAG)) || ((sndnum == PIPEBOMB_EXPLODE || sndnum == LASERTRIP_EXPLODE || sndnum == RPG_EXPLODE)); - bool underwater = ps[screenpeek].cursectnum > -1 && sector[ps[screenpeek].cursectnum].lotag == ST_2_UNDERWATER; - if (explosion) - { - if (underwater) - pitch -= 1024; - } - else - { - if (sndist > 32767 && sp->picnum != MUSICANDSFX && (userflags & (SF_LOOP | SF_MSFX)) == 0) - return -1; + bool underwater = ps[screenpeek].cursectnum > -1 && sector[ps[screenpeek].cursectnum].lotag == ST_2_UNDERWATER; + if (explosion) + { + if (underwater) + pitch -= 1024; + } + else + { + if (sndist > 32767 && sp->picnum != MUSICANDSFX && (userflags & (SF_LOOP | SF_MSFX)) == 0) + return -1; - if (underwater && (userflags & SF_TALK) == 0) - pitch = -768; - } + if (underwater && (userflags & SF_TALK) == 0) + pitch = -768; + } - bool is_playing = soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, sndnum+1); - if (is_playing && sp->picnum != MUSICANDSFX) - S_StopEnvSound(sndnum, spriteNum); + bool is_playing = soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, sndnum+1); + if (is_playing && sp->picnum != MUSICANDSFX) + S_StopEnvSound(sndnum, spriteNum); - int const repeatp = (userflags & SF_LOOP); + int const repeatp = (userflags & SF_LOOP); - if (repeatp && (userflags & SF_ONEINST_INTERNAL) && is_playing) - { - return -1; - } + if (repeatp && (userflags & SF_ONEINST_INTERNAL) && is_playing) + { + return -1; + } - // These explosion sounds originally used some distance hackery to make them louder but due to how the rolloff was set up they always played at full volume as a result. - // I think it is better to lower their attenuation so that they are louder than the rest but still fade in the distance. - // For the original effect, attenuation needs to be set to ATTN_NONE here. - float attenuation; - if (explosion) attenuation = 0.5f; - else attenuation = (userflags & (SF_GLOBAL | SF_DTAG)) == SF_GLOBAL ? ATTN_NONE : ATTN_NORM; + // These explosion sounds originally used some distance hackery to make them louder but due to how the rolloff was set up they always played at full volume as a result. + // I think it is better to lower their attenuation so that they are louder than the rest but still fade in the distance. + // For the original effect, attenuation needs to be set to ATTN_NONE here. + float attenuation; + if (explosion) attenuation = 0.5f; + else attenuation = (userflags & (SF_GLOBAL | SF_DTAG)) == SF_GLOBAL ? ATTN_NONE : ATTN_NORM; - if (userflags & SF_LOOP) flags |= CHANF_LOOP; - auto chan = soundEngine->StartSound(SOURCE_Actor, &sprite[spriteNum], &sndpos, CHAN_AUTO, flags, sndnum+1, attenuation == ATTN_NONE? 0.8f : 1.f, attenuation, nullptr, S_ConvertPitch(pitch)); - return chan ? 0 : -1; + if (userflags & SF_LOOP) flags |= CHANF_LOOP; + auto chan = soundEngine->StartSound(SOURCE_Actor, &sprite[spriteNum], &sndpos, CHAN_AUTO, flags, sndnum+1, attenuation == ATTN_NONE? 0.8f : 1.f, attenuation, nullptr, S_ConvertPitch(pitch)); + return chan ? 0 : -1; } //========================================================================== @@ -457,17 +459,17 @@ int S_PlaySound3D(int sndnum, int spriteNum, const vec3_t* pos, int channel, ECh int S_PlaySound(int sndnum, int channel, EChanFlags flags) { - if (!soundEngine->isValidSoundId(sndnum+1) || !SoundEnabled()) return -1; + if (!soundEngine->isValidSoundId(sndnum+1) || !SoundEnabled()) return -1; - int userflags = S_GetUserFlags(sndnum); - if ((!(snd_speech & 1) && (userflags & SF_TALK)) || ((userflags & SF_ADULT))) - return -1; + int userflags = S_GetUserFlags(sndnum); + if ((!(snd_speech & 1) && (userflags & SF_TALK)) || ((userflags & SF_ADULT))) + return -1; - int const pitch = S_GetPitch(sndnum); + int const pitch = S_GetPitch(sndnum); - if (userflags & SF_LOOP) flags |= CHANF_LOOP; - auto chan = soundEngine->StartSound(SOURCE_None, nullptr, nullptr, channel, flags, sndnum + 1, 0.8f, ATTN_NONE, nullptr, S_ConvertPitch(pitch)); - return chan ? 0 : -1; + if (userflags & SF_LOOP) flags |= CHANF_LOOP; + auto chan = soundEngine->StartSound(SOURCE_None, nullptr, nullptr, channel, flags, sndnum + 1, 0.8f, ATTN_NONE, nullptr, S_ConvertPitch(pitch)); + return chan ? 0 : -1; } //========================================================================== @@ -478,38 +480,38 @@ int S_PlaySound(int sndnum, int channel, EChanFlags flags) int A_PlaySound(int soundNum, int spriteNum, int channel, EChanFlags flags) { - return (unsigned)spriteNum >= MAXSPRITES ? S_PlaySound(soundNum, channel, flags) : - S_PlaySound3D(soundNum, spriteNum, &sprite[spriteNum].pos, channel, flags); + return (unsigned)spriteNum >= MAXSPRITES ? S_PlaySound(soundNum, channel, flags) : + S_PlaySound3D(soundNum, spriteNum, &sprite[spriteNum].pos, channel, flags); } void S_StopEnvSound(int sndNum, int sprNum, int channel) { - if (sprNum < -1 || sprNum >= MAXSPRITES) return; + if (sprNum < -1 || sprNum >= MAXSPRITES) return; - if (sprNum == -1) soundEngine->StopSoundID(sndNum+1); - else - { - if (channel == -1) soundEngine->StopSound(SOURCE_Actor, &sprite[sprNum], -1, sndNum + 1); - else soundEngine->StopSound(SOURCE_Actor, &sprite[sprNum], channel, -1); + if (sprNum == -1) soundEngine->StopSoundID(sndNum+1); + else + { + if (channel == -1) soundEngine->StopSound(SOURCE_Actor, &sprite[sprNum], -1, sndNum + 1); + else soundEngine->StopSound(SOURCE_Actor, &sprite[sprNum], channel, -1); - // StopSound kills the actor reference so this cannot be delayed until ChannelEnded gets called. At that point the actor may also not be valid anymore. - if (S_IsAmbientSFX(sprNum) && sector[sprite[sprNum].sectnum].lotag < 3) // ST_2_UNDERWATER - hittype[sprNum].temp_data[0] = 0; - } + // StopSound kills the actor reference so this cannot be delayed until ChannelEnded gets called. At that point the actor may also not be valid anymore. + if (S_IsAmbientSFX(sprNum) && sector[sprite[sprNum].sectnum].lotag < 3) // ST_2_UNDERWATER + hittype[sprNum].temp_data[0] = 0; + } } void S_ChangeSoundPitch(int soundNum, int spriteNum, int pitchoffset) { - if (spriteNum < -1 || spriteNum >= MAXSPRITES) return; - double expitch = pow(2, pitchoffset / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave. - if (spriteNum == -1) - { - soundEngine->ChangeSoundPitch(SOURCE_Unattached, nullptr, CHAN_AUTO, expitch, soundNum+1); - } - else - { - soundEngine->ChangeSoundPitch(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, expitch, soundNum+1); - } + if (spriteNum < -1 || spriteNum >= MAXSPRITES) return; + double expitch = pow(2, pitchoffset / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave. + if (spriteNum == -1) + { + soundEngine->ChangeSoundPitch(SOURCE_Unattached, nullptr, CHAN_AUTO, expitch, soundNum+1); + } + else + { + soundEngine->ChangeSoundPitch(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, expitch, soundNum+1); + } } //========================================================================== @@ -520,21 +522,21 @@ void S_ChangeSoundPitch(int soundNum, int spriteNum, int pitchoffset) int A_CheckSoundPlaying(int spriteNum, int soundNum, int channel) { - if (spriteNum == -1) return soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, soundNum+1); - if ((unsigned)spriteNum >= MAXSPRITES) return false; - return soundEngine->IsSourcePlayingSomething(SOURCE_Actor, &sprite[spriteNum], channel, soundNum+1); + if (spriteNum == -1) return soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, soundNum+1); + if ((unsigned)spriteNum >= MAXSPRITES) return false; + return soundEngine->IsSourcePlayingSomething(SOURCE_Actor, &sprite[spriteNum], channel, soundNum+1); } // Check if actor <i> is playing any sound. int A_CheckAnySoundPlaying(int spriteNum) { - if ((unsigned)spriteNum >= MAXSPRITES) return false; - return soundEngine->IsSourcePlayingSomething(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, 0); + if ((unsigned)spriteNum >= MAXSPRITES) return false; + return soundEngine->IsSourcePlayingSomething(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, 0); } int S_CheckSoundPlaying(int soundNum) { - return soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, soundNum+1); + return soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, soundNum+1); } //========================================================================== @@ -545,30 +547,30 @@ int S_CheckSoundPlaying(int soundNum) void S_MenuSound(void) { - static int menunum; - int/*static const short*/ menusnds[] = - { - LASERTRIP_EXPLODE, - DUKE_GRUNT, - DUKE_LAND_HURT, - CHAINGUN_FIRE, - SQUISHED, - KICK_HIT, - PISTOL_RICOCHET, - PISTOL_BODYHIT, - PISTOL_FIRE, - SHOTGUN_FIRE, - BOS1_WALK, - RPG_EXPLODE, - PIPEBOMB_BOUNCE, - PIPEBOMB_EXPLODE, - NITEVISION_ONOFF, - RPG_SHOOT, - SELECT_WEAPON - }; - int s = isRR() ? 390 : menusnds[menunum++ % countof(menusnds)]; - if (s != -1) - S_PlaySound(s, CHAN_AUTO, CHANF_UI); + static int menunum; + static const short menusnds[] = + { + LASERTRIP_EXPLODE, + DUKE_GRUNT, + DUKE_LAND_HURT, + CHAINGUN_FIRE, + SQUISHED, + KICK_HIT, + PISTOL_RICOCHET, + PISTOL_BODYHIT, + PISTOL_FIRE, + SHOTGUN_FIRE, + BOS1_WALK, + RPG_EXPLODE, + PIPEBOMB_BOUNCE, + PIPEBOMB_EXPLODE, + NITEVISION_ONOFF, + RPG_SHOOT, + SELECT_WEAPON + }; + int s = isRR() ? 390 : menusnds[menunum++ % countof(menusnds)]; + if (s != -1) + S_PlaySound(s, CHAN_AUTO, CHANF_UI); } //========================================================================== @@ -581,19 +583,18 @@ static bool cd_disabled = false; // This is in case mus_redbook is enabled bu void S_PlayLevelMusic(MapRecord *mi) { - if (isRR() && mi->music.IsEmpty() && mus_redbook && !cd_disabled) return; - Mus_Play(mi->labelName, mi->music, true); + if (isRR() && mi->music.IsEmpty() && mus_redbook && !cd_disabled) return; + Mus_Play(mi->labelName, mi->music, true); } void S_PlaySpecialMusic(unsigned int m) { - if (isRR()) return; // Can only be MUS_LOADING, isRR() does not use it. - auto& musicfn = mapList[m].music; - if (musicfn.IsNotEmpty()) - { - Mus_Play(nullptr, musicfn, true); - - } + if (isRR() || m >= specialmusic.Size()) return; // Can only be MUS_LOADING, isRR() does not use it. + auto& musicfn = specialmusic[m]; + if (musicfn.IsNotEmpty()) + { + Mus_Play(nullptr, musicfn, true); + } } //--------------------------------------------------------------------------- @@ -604,28 +605,28 @@ void S_PlaySpecialMusic(unsigned int m) void S_PlayRRMusic(int newTrack) { - if (!isRR() || !mus_redbook || cd_disabled || currentLevel->music.IsNotEmpty()) - return; - Mus_Stop(); + if (!isRR() || !mus_redbook || cd_disabled || currentLevel->music.IsNotEmpty()) + return; + Mus_Stop(); - for (int i = 0; i < 10; i++) - { - g_cdTrack = newTrack != -1 ? newTrack : g_cdTrack + 1; - if (newTrack != 10 && (g_cdTrack > 9 || g_cdTrack < 2)) - g_cdTrack = 2; + for (int i = 0; i < 10; i++) + { + g_cdTrack = newTrack != -1 ? newTrack : g_cdTrack + 1; + if (newTrack != 10 && (g_cdTrack > 9 || g_cdTrack < 2)) + g_cdTrack = 2; - FStringf filename("track%02d.ogg", g_cdTrack); - if (Mus_Play(nullptr, filename, false)) return; - } - // If none of the tracks managed to start, disable the CD music for this session so that regular music can play if defined. - cd_disabled = true; + FStringf filename("track%02d.ogg", g_cdTrack); + if (Mus_Play(nullptr, filename, false)) return; + } + // If none of the tracks managed to start, disable the CD music for this session so that regular music can play if defined. + cd_disabled = true; } void PlayBonusMusic() { - if (MusicEnabled() && mus_enabled) - S_PlaySound(BONUSMUSIC, CHAN_AUTO, CHANF_UI); + if (MusicEnabled() && mus_enabled) + S_PlaySound(BONUSMUSIC, CHAN_AUTO, CHANF_UI); } END_DUKE_NS diff --git a/source/games/duke/src/sounds.h b/source/games/duke/src/sounds.h index 2fed8c7ec..b489a198e 100644 --- a/source/games/duke/src/sounds.h +++ b/source/games/duke/src/sounds.h @@ -109,6 +109,8 @@ inline bool StartCommentary(int tag, int sprnum) return false; } +extern TArray<FString> specialmusic; + END_DUKE_NS diff --git a/source/games/duke/src/zz_premap.cpp b/source/games/duke/src/zz_premap.cpp index 5fafbe15f..a858555a3 100644 --- a/source/games/duke/src/zz_premap.cpp +++ b/source/games/duke/src/zz_premap.cpp @@ -133,13 +133,13 @@ void G_NewGame(MapRecord *map, int skillNum) void resetpspritevars(int gameMode); -static inline void clearfrags(void) +void clearfrags(void) { for (int i = 0; i < ud.multimode; i++) { playerdata_t *const pPlayerData = &g_player[i]; pPlayerData->ps->frag = pPlayerData->ps->fraggedself = 0; - Bmemset(pPlayerData->frags, 0, sizeof(pPlayerData->frags)); + memset(pPlayerData->frags, 0, sizeof(pPlayerData->frags)); } } diff --git a/source/rr/src/sounds.cpp b/source/rr/src/sounds.cpp index 91f23326e..c6e767935 100644 --- a/source/rr/src/sounds.cpp +++ b/source/rr/src/sounds.cpp @@ -30,6 +30,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_RR_NS +extern MapRecord userMapRecord; + class DukeSoundEngine : public SoundEngine { // client specific parts of the sound engine go in this class.