diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index d30d880d6..2bb26e7c9 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -542,6 +542,7 @@ void StartLevel(GAMEOPTIONS *gameOptions) return; } char levelName[BMAX_PATH]; + currentLevel = &mapList[gGameOptions.nEpisode * kMaxLevels + gGameOptions.nLevel]; STAT_NewLevel(gameOptions->zLevelName); G_LoadMapHack(levelName, gameOptions->zLevelName); wsrand(gameOptions->uMapCRC); @@ -1444,9 +1445,8 @@ static int32_t S_DefineMusic(const char *ID, const char *name) return -1; } - int nEpisode = sel/kMaxLevels; - int nLevel = sel%kMaxLevels; - return S_DefineAudioIfSupported(gEpisodeInfo[nEpisode].at28[nLevel].atd0, name); + quoteMgr.InitializeQuote(sel, name); + return 0; } static int parsedefinitions_game(scriptfile *, int); @@ -1988,9 +1988,7 @@ bool fileExistsRFF(int id, const char *ext) { int sndTryPlaySpecialMusic(int nMusic) { - int nEpisode = nMusic/kMaxLevels; - int nLevel = nMusic%kMaxLevels; - if (Mus_Play(gEpisodeInfo[nEpisode].at28[nLevel].at0, gEpisodeInfo[nEpisode].at28[nLevel].atd0, true)) + if (Mus_Play(nullptr, quoteMgr.GetQuote(nMusic), true)) { return 0; } diff --git a/source/blood/src/levels.cpp b/source/blood/src/levels.cpp index 7cc35c58f..b778153b4 100644 --- a/source/blood/src/levels.cpp +++ b/source/blood/src/levels.cpp @@ -146,48 +146,48 @@ void CheckKeyAbend(const char *pzSection, const char *pzKey) ThrowError("Key %s expected in section [%s] of BLOOD.INI", pzKey, pzSection); } -LEVELINFO * levelGetInfoPtr(int nEpisode, int nLevel) +MapRecord * levelGetInfoPtr(int nEpisode, int nLevel) { dassert(nEpisode >= 0 && nEpisode < gEpisodeCount); EPISODEINFO *pEpisodeInfo = &gEpisodeInfo[nEpisode]; dassert(nLevel >= 0 && nLevel < pEpisodeInfo->nLevels); - return &pEpisodeInfo->at28[nLevel]; + return &pEpisodeInfo->levels[nLevel]; } -char * levelGetFilename(int nEpisode, int nLevel) +const char * levelGetFilename(int nEpisode, int nLevel) { dassert(nEpisode >= 0 && nEpisode < gEpisodeCount); EPISODEINFO *pEpisodeInfo = &gEpisodeInfo[nEpisode]; dassert(nLevel >= 0 && nLevel < pEpisodeInfo->nLevels); - return pEpisodeInfo->at28[nLevel].at0; + return pEpisodeInfo->levels[nLevel].labelName; } -char * levelGetMessage(int nMessage) +const char * levelGetMessage(int nMessage) { int nEpisode = gGameOptions.nEpisode; int nLevel = gGameOptions.nLevel; dassert(nMessage < kMaxMessages); - char *pMessage = gEpisodeInfo[nEpisode].at28[nLevel].atec[nMessage]; + const char *pMessage = gEpisodeInfo[nEpisode].levels[nLevel].GetMessage(nMessage); if (*pMessage == 0) return NULL; return pMessage; } -char * levelGetTitle(void) +const char * levelGetTitle(void) { int nEpisode = gGameOptions.nEpisode; int nLevel = gGameOptions.nLevel; - char *pTitle = gEpisodeInfo[nEpisode].at28[nLevel].at90; + const char *pTitle = gEpisodeInfo[nEpisode].levels[nLevel].DisplayName(); if (*pTitle == 0) return NULL; return pTitle; } -char * levelGetAuthor(void) +const char * levelGetAuthor(void) { int nEpisode = gGameOptions.nEpisode; int nLevel = gGameOptions.nLevel; - char *pAuthor = gEpisodeInfo[nEpisode].at28[nLevel].atb0; + const char *pAuthor = gEpisodeInfo[nEpisode].levels[nLevel].author; if (*pAuthor == 0) return NULL; return pAuthor; @@ -197,26 +197,27 @@ void levelSetupOptions(int nEpisode, int nLevel) { gGameOptions.nEpisode = nEpisode; gGameOptions.nLevel = nLevel; - strcpy(gGameOptions.zLevelName, gEpisodeInfo[nEpisode].at28[nLevel].at0); + strcpy(gGameOptions.zLevelName, gEpisodeInfo[nEpisode].levels[nLevel].labelName); gGameOptions.uMapCRC = dbReadMapCRC(gGameOptions.zLevelName); - gGameOptions.nTrackNumber = gEpisodeInfo[nEpisode].at28[nLevel].ate0; + gGameOptions.nTrackNumber = gEpisodeInfo[nEpisode].levels[nLevel].cdSongId; } -void levelLoadMapInfo(IniFile *pIni, LEVELINFO *pLevelInfo, const char *pzSection) +void levelLoadMapInfo(IniFile *pIni, MapRecord *pLevelInfo, const char *pzSection, int epinum, int mapnum) { char buffer[16]; - strncpy(pLevelInfo->at90, pIni->GetKeyString(pzSection, "Title", pLevelInfo->at0), 31); - strncpy(pLevelInfo->atb0, pIni->GetKeyString(pzSection, "Author", ""), 31); - strncpy(pLevelInfo->atd0, pIni->GetKeyString(pzSection, "Song", ""), BMAX_PATH); - pLevelInfo->ate0 = pIni->GetKeyInt(pzSection, "Track", -1); - pLevelInfo->ate4 = pIni->GetKeyInt(pzSection, "EndingA", -1); - pLevelInfo->ate8 = pIni->GetKeyInt(pzSection, "EndingB", -1); - pLevelInfo->at8ec = pIni->GetKeyInt(pzSection, "Fog", -0); - pLevelInfo->at8ed = pIni->GetKeyInt(pzSection, "Weather", -0); + pLevelInfo->SetName(pIni->GetKeyString(pzSection, "Title", pLevelInfo->labelName)); + pLevelInfo->author = pIni->GetKeyString(pzSection, "Author", ""); + pLevelInfo->music.Format("%s.%s", pIni->GetKeyString(pzSection, "Song", ""), ".mid"); + pLevelInfo->cdSongId = pIni->GetKeyInt(pzSection, "Track", -1); + pLevelInfo->nextLevel = pIni->GetKeyInt(pzSection, "EndingA", -1); //if (pLevelInfo->nextLevel >= 0) pLevelInfo->nextLevel +epinum * kMaxLevels; + pLevelInfo->nextSecret = pIni->GetKeyInt(pzSection, "EndingB", -1); //if (pLevelInfo->nextSecret >= 0) pLevelInfo->nextSecret + epinum * kMaxLevels; + pLevelInfo->fog = pIni->GetKeyInt(pzSection, "Fog", -0); + pLevelInfo->weather = pIni->GetKeyInt(pzSection, "Weather", -0); + pLevelInfo->messageStart = 1024 + ((epinum * kMaxLevels) + mapnum) * kMaxMessages; for (int i = 0; i < kMaxMessages; i++) { sprintf(buffer, "Message%d", i+1); - strncpy(pLevelInfo->atec[i], pIni->GetKeyString(pzSection, buffer, ""), 63); + quoteMgr.InitializeQuote(pLevelInfo->messageStart + i, pIni->GetKeyString(pzSection, buffer, ""), true); } } @@ -226,7 +227,7 @@ void levelLoadDefaults(void) char buffer2[16]; levelInitINI(G_ConFile()); // This doubles for the INI in the global code. memset(gEpisodeInfo, 0, sizeof(gEpisodeInfo)); - strncpy(gEpisodeInfo[MUS_INTRO/kMaxLevels].at28[MUS_INTRO%kMaxLevels].atd0, "PESTIS", BMAX_PATH); + quoteMgr.InitializeQuote(MUS_INTRO, "PESTIS.MID"); int i; for (i = 0; i < kMaxEpisodes; i++) { @@ -253,17 +254,19 @@ void levelLoadDefaults(void) pEpisodeInfo->cutALevel = BloodINI->GetKeyInt(buffer, "CutSceneALevel", 0); if (pEpisodeInfo->cutALevel > 0) pEpisodeInfo->cutALevel--; + pEpisodeInfo->levels = mapList + i * kMaxLevels; int j; for (j = 0; j < kMaxLevels; j++) { - LEVELINFO *pLevelInfo = &pEpisodeInfo->at28[j]; + auto pLevelInfo = &pEpisodeInfo->levels[j]; sprintf(buffer2, "Map%d", j+1); if (!BloodINI->KeyExists(buffer, buffer2)) break; const char *pMap = BloodINI->GetKeyString(buffer, buffer2, NULL); CheckSectionAbend(pMap); - strncpy(pLevelInfo->at0, pMap, BMAX_PATH); - levelLoadMapInfo(BloodINI, pLevelInfo, pMap); + pLevelInfo->labelName = pMap; + pLevelInfo->fileName.Format("%s.map", pMap); + levelLoadMapInfo(BloodINI, pLevelInfo, pMap, i, j); } pEpisodeInfo->nLevels = j; } @@ -289,24 +292,24 @@ void levelAddUserMap(const char *pzMap) } nLevel = pEpisodeInfo->nLevels++; } - LEVELINFO *pLevelInfo = &pEpisodeInfo->at28[nLevel]; + auto pLevelInfo = &pEpisodeInfo->levels[nLevel]; ChangeExtension(buffer, ""); - strncpy(pLevelInfo->at0, buffer, BMAX_PATH); - levelLoadMapInfo(&UserINI, pLevelInfo, NULL); + pLevelInfo->name = buffer; + levelLoadMapInfo(&UserINI, pLevelInfo, NULL, nEpisode, nLevel); gGameOptions.nEpisode = nEpisode; gGameOptions.nLevel = nLevel; - gGameOptions.uMapCRC = dbReadMapCRC(pLevelInfo->at0); - strcpy(gGameOptions.zLevelName, pLevelInfo->at0); + gGameOptions.uMapCRC = dbReadMapCRC(pLevelInfo->name); + strcpy(gGameOptions.zLevelName, pLevelInfo->name); } void levelGetNextLevels(int nEpisode, int nLevel, int *pnEndingA, int *pnEndingB) { dassert(pnEndingA != NULL && pnEndingB != NULL); - LEVELINFO *pLevelInfo = &gEpisodeInfo[nEpisode].at28[nLevel]; - int nEndingA = pLevelInfo->ate4; + auto pLevelInfo = &gEpisodeInfo[nEpisode].levels[nLevel]; + int nEndingA = pLevelInfo->nextLevel; if (nEndingA >= 0) nEndingA--; - int nEndingB = pLevelInfo->ate8; + int nEndingB = pLevelInfo->nextSecret; if (nEndingB >= 0) nEndingB--; *pnEndingA = nEndingA; @@ -396,14 +399,14 @@ int levelGetMusicIdx(const char *str) bool levelTryPlayMusic(int nEpisode, int nLevel, bool bSetLevelSong) { char buffer[BMAX_PATH]; - if (mus_redbook && gEpisodeInfo[nEpisode].at28[nLevel].ate0 > 0) - snprintf(buffer, BMAX_PATH, "blood%02i.ogg", gEpisodeInfo[nEpisode].at28[nLevel].ate0); + if (mus_redbook && gEpisodeInfo[nEpisode].levels[nLevel].cdSongId > 0) + snprintf(buffer, BMAX_PATH, "blood%02i.ogg", gEpisodeInfo[nEpisode].levels[nLevel].cdSongId); else { - strncpy(buffer, gEpisodeInfo[nEpisode].at28[nLevel].atd0, BMAX_PATH); + strncpy(buffer, gEpisodeInfo[nEpisode].levels[nLevel].music, BMAX_PATH); } if (!strchr(buffer, '.')) strcat(buffer, ".mid"); - return !!Mus_Play(gEpisodeInfo[nEpisode].at28[nLevel].at0, buffer, true); + return !!Mus_Play(gEpisodeInfo[nEpisode].levels[nLevel].labelName, buffer, true); } void levelTryPlayMusicOrNothing(int nEpisode, int nLevel) diff --git a/source/blood/src/levels.h b/source/blood/src/levels.h index e0b5bb9d7..1d6aec8e2 100644 --- a/source/blood/src/levels.h +++ b/source/blood/src/levels.h @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #pragma once #include "common_game.h" #include "inifile.h" +#include "mapinfo.h" BEGIN_BLD_NS @@ -68,27 +69,13 @@ enum { MUS_LOADING = MUS_FIRST_SPECIAL + 1, }; -struct LEVELINFO -{ - char at0[BMAX_PATH]; // Filename - char at90[32]; // Title - char atb0[32]; // Author - char atd0[BMAX_PATH]; // Song; - int ate0; // SongId - int ate4; // EndingA - int ate8; // EndingB - char atec[kMaxMessages][64]; // Messages - char at8ec; // Fog - char at8ed; // Weather -}; // 0x8ee bytes - struct EPISODEINFO { //char at0[32]; removed, so that the global episode name table can be used for consistency int nLevels; unsigned int bloodbath : 1; unsigned int cutALevel : 4; - LEVELINFO at28[kMaxLevels]; + MapRecord* levels; // points into the global table. char at8f08[BMAX_PATH]; char at8f98[BMAX_PATH]; int at9028; @@ -118,13 +105,12 @@ void levelSetupSecret(int nCount); void levelTriggerSecret(int nSecret); void CheckSectionAbend(const char *pzSection); void CheckKeyAbend(const char *pzSection, const char *pzKey); -LEVELINFO * levelGetInfoPtr(int nEpisode, int nLevel); -char * levelGetFilename(int nEpisode, int nLevel); -char * levelGetMessage(int nMessage); -char * levelGetTitle(void); -char * levelGetAuthor(void); +MapRecord * levelGetInfoPtr(int nEpisode, int nLevel); +const char * levelGetFilename(int nEpisode, int nLevel); +const char * levelGetMessage(int nMessage); +const char * levelGetTitle(void); +const char * levelGetAuthor(void); void levelSetupOptions(int nEpisode, int nLevel); -void levelLoadMapInfo(IniFile *pIni, LEVELINFO *pLevelInfo, const char *pzSection); void levelLoadDefaults(void); void levelAddUserMap(const char *pzMap); // EndingA is normal ending, EndingB is secret level diff --git a/source/blood/src/loadsave.cpp b/source/blood/src/loadsave.cpp index f35071504..a42cf95e3 100644 --- a/source/blood/src/loadsave.cpp +++ b/source/blood/src/loadsave.cpp @@ -209,13 +209,6 @@ bool GameInterface::SaveGame(FSaveGameNode* node) Printf(TEXTCOLOR_RED "%s\n", err.what()); return false; } - auto & li = gEpisodeInfo[gGameOptions.nEpisode].at28[gGameOptions.nLevel]; - // workaround until the level info here has been transitioned. - MapRecord mr; - mr.name = li.at90; - mr.labelName = li.at0; - mr.fileName.Format("%s.map", li.at0); - currentLevel = &mr; G_WriteSaveHeader(node->SaveTitle); LoadSave::hSFile = NULL; diff --git a/source/blood/src/map2d.cpp b/source/blood/src/map2d.cpp index 971118a38..e8532289c 100644 --- a/source/blood/src/map2d.cpp +++ b/source/blood/src/map2d.cpp @@ -197,8 +197,8 @@ void CViewMap::sub_25C74(void) videoClearScreen(0); renderDrawMapView(x,y,nZoom>>2,angle); sub_2541C(x,y,nZoom>>2,angle); - char *pTitle = levelGetTitle(); - char *pFilename = levelGetFilename(gGameOptions.nEpisode, gGameOptions.nLevel); + const char *pTitle = levelGetTitle(); + const char *pFilename = levelGetFilename(gGameOptions.nEpisode, gGameOptions.nLevel); if (pTitle) sprintf(pBuffer, "%s: %s", pFilename, pTitle); else diff --git a/source/blood/src/triggers.cpp b/source/blood/src/triggers.cpp index f1c310bff..6814d62c5 100644 --- a/source/blood/src/triggers.cpp +++ b/source/blood/src/triggers.cpp @@ -4769,7 +4769,7 @@ void trInit(void) void trTextOver(int nId) { - char *pzMessage = levelGetMessage(nId); + const char *pzMessage = levelGetMessage(nId); if (pzMessage) viewSetMessage(pzMessage, VanillaMode() ? 0 : 8, MESSAGE_PRIORITY_INI); // 8: gold } diff --git a/source/common/mapinfo.h b/source/common/mapinfo.h index b5882bc00..8ab0a1af9 100644 --- a/source/common/mapinfo.h +++ b/source/common/mapinfo.h @@ -2,6 +2,10 @@ #include "gstrings.h" #include "cmdlib.h" +#include "quotemgr.h" +#ifdef GetMessage +#undef GetMessage // Windows strikes... +#endif // Localization capable replacement of the game specific solutions. @@ -18,21 +22,21 @@ enum struct MapRecord { - int parTime; - int designerTime; + int parTime = -1; + int designerTime = -1; FString fileName; FString labelName; FString name; FString music; - int cdSongId; + int cdSongId = -1; + int flags = -1; // The rest is only used by Blood - int nextLevel; - int nextSecret; - int messageStart; // messages are stored in the quote array to reduce clutter. + int nextLevel = -1; + int nextSecret = -1; + int messageStart = 0; // messages are stored in the quote array to reduce clutter. FString author; - // bool fog, weather; // Blood defines these but they aren't used. - int flags; + int8_t fog = -1, weather = -1; // Blood defines these but they aren't used. const char *DisplayName() { @@ -49,6 +53,10 @@ struct MapRecord fileName = n; labelName = ExtractFileBase(n); } + const char* GetMessage(int num) + { + return quoteMgr.GetQuote(messageStart + num); + } }; diff --git a/source/common/statistics.cpp b/source/common/statistics.cpp index ad9b31020..8405e541c 100644 --- a/source/common/statistics.cpp +++ b/source/common/statistics.cpp @@ -601,7 +601,7 @@ CCMD(printstats) ADD_STAT(statistics) { - if (*StartEpisode == 0 || *LevelName == 0) return; + if (*StartEpisode == 0 || *LevelName == 0) return ""; StoreLevelStats(); // Refresh the current level's results. return GetStatString(); } diff --git a/source/duke3d/src/premap.cpp b/source/duke3d/src/premap.cpp index e42bc2ad2..4909abf05 100644 --- a/source/duke3d/src/premap.cpp +++ b/source/duke3d/src/premap.cpp @@ -419,7 +419,7 @@ void G_CacheMapData(void) if (ud.recstat == 2) return; - S_TryPlaySpecialMusic(MUS_LOADING); + //S_TryPlaySpecialMusic(MUS_LOADING); uint32_t const cacheStartTime = timerGetTicks(); diff --git a/source/duke3d/src/sounds.cpp b/source/duke3d/src/sounds.cpp index 68b7e83cc..48949bdee 100644 --- a/source/duke3d/src/sounds.cpp +++ b/source/duke3d/src/sounds.cpp @@ -149,7 +149,7 @@ void S_PlayLevelMusicOrNothing(unsigned int m) { // Thanks to scripting that stupid slot hijack cannot be refactored - but we'll store the real data elsewhere anyway! auto &mr = m == USERMAPMUSICFAKESLOT ? userMapRecord : mapList[m]; - Mus_Play(mr.fileName, mr.music, true); + Mus_Play(mr.labelName, mr.music, true); S_SetMusicIndex(m); } } diff --git a/source/rr/src/sounds.cpp b/source/rr/src/sounds.cpp index 72cb948a0..b86632a8f 100644 --- a/source/rr/src/sounds.cpp +++ b/source/rr/src/sounds.cpp @@ -125,7 +125,7 @@ void S_MenuSound(void) void S_PlayLevelMusicOrNothing(unsigned int m) { - Mus_Play(mapList[m].fileName, RR ? nullptr : mapList[m].music, true); + Mus_Play(mapList[m].labelName, RR ? nullptr : mapList[m].music, true); } int S_TryPlaySpecialMusic(unsigned int m)