From e9385ed4e8e3b052e0c24aa34beb899bea3ca970 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 May 2021 09:08:57 +0200 Subject: [PATCH] - adapted Blood to the new level progression features and simplified several parts, particularly the clumsy retrieval of the next level. Some cheats in Duke will not work correctly with this commit! --- source/core/cheats.cpp | 2 +- source/core/mapinfo.cpp | 57 +++++++++++++++------ source/core/mapinfo.h | 4 +- source/games/blood/src/blood.cpp | 41 +++++---------- source/games/blood/src/endgame.cpp | 1 - source/games/blood/src/levels.cpp | 78 ++++++++++++----------------- source/games/blood/src/levels.h | 3 +- source/games/blood/src/loadsave.cpp | 1 - source/games/blood/src/messages.cpp | 4 +- source/games/blood/src/nnexts.cpp | 8 +-- source/games/duke/src/cheats.cpp | 6 +-- 11 files changed, 100 insertions(+), 105 deletions(-) diff --git a/source/core/cheats.cpp b/source/core/cheats.cpp index 72812e623..6cd00d6cd 100644 --- a/source/core/cheats.cpp +++ b/source/core/cheats.cpp @@ -294,7 +294,7 @@ static MapRecord* levelwarp_common(FCommandLine& argv, const char *cmdname, cons Printf(PRINT_BOLD, "Invalid level! Numbers must be > 0\n"); return nullptr; } - auto map = FindMapByLevelNum(numparm == 1 ? m : makelevelnum(e - 1, m - 1)); + auto map = FindMapByLevelNum(numparm == 1 ? m : makelevelnum(e, m)); if (!map) { if (numparm == 2) Printf(PRINT_BOLD, "Level E%s L%s not found!\n", argv[1], argv[2]); diff --git a/source/core/mapinfo.cpp b/source/core/mapinfo.cpp index 74ed92fe2..253d1a092 100644 --- a/source/core/mapinfo.cpp +++ b/source/core/mapinfo.cpp @@ -84,10 +84,10 @@ CCMD(mapinfo) if (clus.intro.isdefined() || clus.outro.isdefined()) { Printf("Cluster %d\n\tName = '%s'\n", clus.index, clus.name.GetChars()); - if (clus.intro.function.IsNotEmpty()) Printf("\tIntro function = %d\n", clus.intro.function.GetChars()); - if (clus.intro.video.IsNotEmpty()) Printf("\tIntro video = %d\n", clus.intro.video.GetChars()); - if (clus.outro.function.IsNotEmpty()) Printf("\tOutro function = %d\n", clus.outro.function.GetChars()); - if (clus.outro.video.IsNotEmpty()) Printf("\tOutro video = %d\n", clus.outro.video.GetChars()); + if (clus.intro.function.IsNotEmpty()) Printf("\tIntro function = %s\n", clus.intro.function.GetChars()); + if (clus.intro.video.IsNotEmpty()) Printf("\tIntro video = %s\n", clus.intro.video.GetChars()); + if (clus.outro.function.IsNotEmpty()) Printf("\tOutro function = %s\n", clus.outro.function.GetChars()); + if (clus.outro.video.IsNotEmpty()) Printf("\tOutro video = %s\n", clus.outro.video.GetChars()); Printf("}\n"); } } @@ -108,10 +108,10 @@ CCMD(mapinfo) if (map->cdSongId > 0) Printf("\tCD track = %d\n", map->cdSongId); if (map->parTime) Printf("\tPar Time = %d\n", map->parTime); if (map->designerTime) Printf("\tPar Time = %d\n", map->designerTime); - if (map->intro.function.IsNotEmpty()) Printf("\tIntro function = %d\n", map->intro.function.GetChars()); - if (map->intro.video.IsNotEmpty()) Printf("\tIntro video = %d\n", map->intro.video.GetChars()); - if (map->outro.function.IsNotEmpty()) Printf("\tOutro function = %d\n", map->outro.function.GetChars()); - if (map->outro.video.IsNotEmpty()) Printf("\tOutro video = %d\n", map->outro.video.GetChars()); + if (map->intro.function.IsNotEmpty()) Printf("\tIntro function = %s\n", map->intro.function.GetChars()); + if (map->intro.video.IsNotEmpty()) Printf("\tIntro video = %s\n", map->intro.video.GetChars()); + if (map->outro.function.IsNotEmpty()) Printf("\tOutro function = %s\n", map->outro.function.GetChars()); + if (map->outro.video.IsNotEmpty()) Printf("\tOutro video = %s\n", map->outro.video.GetChars()); Printf("}\n"); } else @@ -173,6 +173,41 @@ VolumeRecord* AllocateVolume() { return &volumes[volumes.Reserve(1)]; } + +MapRecord* FindMapByIndexOnly(int cluster, int num) +{ + for (auto& map : mapList) + { + if (map->mapindex == num && map->cluster == cluster) return map.Data(); + } + return nullptr; +} + +MapRecord* FindMapByIndex(int cluster, int num) +{ + auto map = FindMapByLevelNum(num); + if (!map) map = FindMapByIndexOnly(cluster, num); // modern definitions take precedence. + return map; +} + +MapRecord* FindNextMap(MapRecord* thismap) +{ + MapRecord* next = nullptr; + if (!thismap->NextMap.Compare("-")) return nullptr; // '-' means to forcibly end the game here. + if (thismap->NextMap.IsNotEmpty()) next = FindMapByName(thismap->NextMap); + if (!next) next = FindMapByLevelNum(thismap->levelNumber); + return next; +} + +MapRecord* FindNextSecretMap(MapRecord* thismap) +{ + MapRecord* next = nullptr; + if (!thismap->NextSecret.Compare("-")) return nullptr; // '-' means to forcibly end the game here. + if (thismap->NextSecret.IsNotEmpty()) next = FindMapByName(thismap->NextSecret); + return next? next : FindNextMap(thismap); +} + + // return a map whose cluster and map number matches. // if there's only one map with the given level number return that. MapRecord* FindMapByClusterAndLevelNum(int cluster, int num) @@ -195,12 +230,6 @@ MapRecord* FindMapByClusterAndLevelNum(int cluster, int num) return nullptr; } -MapRecord *FindNextMap(MapRecord *thismap) -{ - if (thismap->nextLevel != -1) return FindMapByLevelNum(thismap->nextLevel); - return FindMapByLevelNum(thismap->levelNumber+1); -} - bool SetMusicForMap(const char* mapname, const char* music, bool namehack) { static const char* specials[] = { "intro", "briefing", "loading" }; diff --git a/source/core/mapinfo.h b/source/core/mapinfo.h index 35e451d54..76d44a95a 100644 --- a/source/core/mapinfo.h +++ b/source/core/mapinfo.h @@ -205,9 +205,11 @@ bool SetMusicForMap(const char* mapname, const char* music, bool namehack = fals MapRecord *FindMapByName(const char *nm); MapRecord *FindMapByLevelNum(int num); +MapRecord* FindMapByIndexOnly(int clst, int num); // this is for map setup where fallbacks are undesirable. +MapRecord* FindMapByIndex(int clst, int num); MapRecord* FindMapByClusterAndLevelNum(int clst, int num); -inline MapRecord* FindMapByIndexOnly(int clst, int num) { return FindMapByClusterAndLevelNum(clst, num); } MapRecord *FindNextMap(MapRecord *thismap); +MapRecord* FindNextSecretMap(MapRecord* thismap); MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic = nullptr); MapRecord* AllocateMap(); diff --git a/source/games/blood/src/blood.cpp b/source/games/blood/src/blood.cpp index 9c7ddf997..4af549d52 100644 --- a/source/games/blood/src/blood.cpp +++ b/source/games/blood/src/blood.cpp @@ -80,7 +80,7 @@ void EndLevel(void) seqKillAll(); } -void StartLevel(MapRecord* level) +void StartLevel(MapRecord* level, bool newgame) { if (!level) return; gFrameCount = 0; @@ -97,14 +97,14 @@ void StartLevel(MapRecord* level) /////// } #if 0 - else if (gGameOptions.nGameType > 0 && !(gGameOptions.uGameFlags & GF_AdvanceLevel)) + else if (gGameOptions.nGameType > 0 && newgame) { // todo gBlueFlagDropped = false; gRedFlagDropped = false; } #endif - if (gGameOptions.uGameFlags & GF_AdvanceLevel) + if (!newgame) { for (int i = connecthead; i >= 0; i = connectpoint2[i]) { @@ -182,13 +182,13 @@ void StartLevel(MapRecord* level) evInit(); for (int i = connecthead; i >= 0; i = connectpoint2[i]) { - if (!(gGameOptions.uGameFlags & GF_AdvanceLevel)) + if (newgame) { playerInit(i, 0); } playerStart(i, 1); } - if (gGameOptions.uGameFlags & GF_AdvanceLevel) + if (!newgame) { for (int i = connecthead; i >= 0; i = connectpoint2[i]) { @@ -205,7 +205,6 @@ void StartLevel(MapRecord* level) pPlayer->nextWeapon = gPlayerTemp[i].nextWeapon; } } - gGameOptions.uGameFlags &= ~(GF_AdvanceLevel|GF_EndGame); PreloadCache(); InitMirrors(); trInit(); @@ -224,11 +223,11 @@ void StartLevel(MapRecord* level) } -void NewLevel(MapRecord *sng, int skill) +void NewLevel(MapRecord *sng, int skill, bool newgame) { if (skill != -1) gGameOptions.nDifficulty = skill; gSkill = gGameOptions.nDifficulty; - StartLevel(sng); + StartLevel(sng, newgame); gameaction = ga_level; } @@ -236,13 +235,12 @@ void GameInterface::NewGame(MapRecord *sng, int skill, bool) { gGameOptions.uGameFlags = 0; cheatReset(); - NewLevel(sng, skill); + NewLevel(sng, skill, true); } void GameInterface::NextLevel(MapRecord *map, int skill) { - gGameOptions.uGameFlags = GF_AdvanceLevel; - NewLevel(map, skill); + NewLevel(map, skill, false); } void GameInterface::Ticker() @@ -313,25 +311,12 @@ void GameInterface::Ticker() team_ticker[i] = 0; } - int gf = gGameOptions.uGameFlags; - - if (gf & GF_AdvanceLevel) + if (gGameOptions.uGameFlags & GF_AdvanceLevel) { + gGameOptions.uGameFlags &= ~GF_AdvanceLevel; seqKillAll(); - - if (gf & GF_EndGame) - { - STAT_Update(true); - CompleteLevel(nullptr); - } - else - { - STAT_Update(false); - // Fixme: Link maps, not episode/level pairs. - int ep = volfromlevelnum(currentLevel->levelNumber); - auto map = FindMapByLevelNum(makelevelnum(ep, gNextLevel)); - CompleteLevel(map); - } + STAT_Update(gNextLevel == nullptr); + CompleteLevel(gNextLevel); } r_NoInterpolate = false; } diff --git a/source/games/blood/src/endgame.cpp b/source/games/blood/src/endgame.cpp index 497e3046b..38b73a489 100644 --- a/source/games/blood/src/endgame.cpp +++ b/source/games/blood/src/endgame.cpp @@ -55,7 +55,6 @@ void GameInterface::LevelCompleted(MapRecord *map, int skill) { soundEngine->StopAllChannels(); gameaction = map? ga_nextlevel : ga_creditsmenu; - if (!map) gGameOptions.uGameFlags &= ~(GF_AdvanceLevel | GF_EndGame); }); } diff --git a/source/games/blood/src/levels.cpp b/source/games/blood/src/levels.cpp index 7d42fbe43..b69ab4527 100644 --- a/source/games/blood/src/levels.cpp +++ b/source/games/blood/src/levels.cpp @@ -39,7 +39,7 @@ GAMEOPTIONS gSingleGameOptions = { }; int gSkill = 2; -int gNextLevel; // fixme: let this contain a full level number. +MapRecord* gNextLevel; char BloodIniFile[BMAX_PATH] = "BLOOD.INI"; bool bINIOverride = false; @@ -91,15 +91,16 @@ void CheckKeyAbend(const char *pzSection, const char *pzKey) } -void levelLoadMapInfo(IniFile *pIni, MapRecord *pLevelInfo, const char *pzSection, int epinum, int mapnum) + +void levelLoadMapInfo(IniFile* pIni, MapRecord* pLevelInfo, const char* pzSection, int epinum, int mapnum, int* nextmap, int* nextsecret) { char buffer[16]; pLevelInfo->SetName(pIni->GetKeyString(pzSection, "Title", pLevelInfo->labelName)); pLevelInfo->Author = pIni->GetKeyString(pzSection, "Author", ""); pLevelInfo->music = pIni->GetKeyString(pzSection, "Song", ""); DefaultExtension(pLevelInfo->music, ".mid"); pLevelInfo->cdSongId = pIni->GetKeyInt(pzSection, "Track", -1); - pLevelInfo->nextLevel = pIni->GetKeyInt(pzSection, "EndingA", -1); - pLevelInfo->nextSecret = pIni->GetKeyInt(pzSection, "EndingB", -1); + *nextmap = pIni->GetKeyInt(pzSection, "EndingA", 0); + *nextsecret = pIni->GetKeyInt(pzSection, "EndingB", 0); pLevelInfo->fog = pIni->GetKeyInt(pzSection, "Fog", -0); pLevelInfo->weather = pIni->GetKeyInt(pzSection, "Weather", -0); for (int i = 0; i < kMaxMessages; i++) @@ -178,11 +179,11 @@ void levelLoadDefaults(void) csB.sound = soundEngine->FindSound(cleanPath(BloodINI->GetKeyString(buffer, "CutWavB", ""))); //pEpisodeInfo->bloodbath = BloodINI->GetKeyInt(buffer, "BloodBathOnly", 0); - cutALevel = BloodINI->GetKeyInt(buffer, "CutSceneALevel", 0) - 1; - if (cutALevel < 0) cutALevel = 0; + cutALevel = BloodINI->GetKeyInt(buffer, "CutSceneALevel", 0); + if (cutALevel < 1) cutALevel = 1; - int j; - for (j = 1; j <= kMaxLevels; j++) + int nextmaps[kMaxLevels]{}, nextsecrets[kMaxLevels]{}; + for (int j = 1; j <= kMaxLevels; j++) { sprintf(buffer2, "Map%d", j); if (!BloodINI->KeyExists(buffer, buffer2)) @@ -190,13 +191,13 @@ void levelLoadDefaults(void) auto pLevelInfo = AllocateMap(); const char *pMap = BloodINI->GetKeyString(buffer, buffer2, NULL); CheckSectionAbend(pMap); - SetLevelNum(pLevelInfo, makelevelnum(i-1, j-1)); + SetLevelNum(pLevelInfo, makelevelnum(i, j)); pLevelInfo->cluster = i; pLevelInfo->mapindex = j; pLevelInfo->labelName = pMap; if (j == 1) volume->startmap = pLevelInfo->labelName; pLevelInfo->fileName.Format("%s.map", pMap); - levelLoadMapInfo(BloodINI, pLevelInfo, pMap, i, j); + levelLoadMapInfo(BloodINI, pLevelInfo, pMap, i, j, &nextmaps[j - 1], &nextsecrets[j - 1]); if (j == cutALevel) { CutsceneDef& csA = pLevelInfo->intro; @@ -206,47 +207,34 @@ void levelLoadDefaults(void) csA.sound = soundEngine->FindSound(cleanPath(BloodINI->GetKeyString(buffer, "CutWavA", ""))); } } + // Now resolve the level links + for (int j = 1; j <= kMaxLevels; j++) + { + auto map = FindMapByIndexOnly(i, j); + if (map) + { + if (nextmaps[j - 1] > 0) + { + auto nmap = FindMapByIndexOnly(i, nextmaps[j - 1]); + if (nmap) map->NextMap = nmap->labelName; + else map->NextMap = "-"; + } + if (nextsecrets[j - 1] > 0) + { + auto nmap = FindMapByIndexOnly(i, nextsecrets[j - 1]); + if (nmap) map->NextSecret = nmap->labelName; + else map->NextSecret = "-"; + } + } + } } } -void levelGetNextLevels(int *pnEndingA, int *pnEndingB) -{ - assert(pnEndingA != NULL && pnEndingB != NULL); - int nEndingA = currentLevel->nextLevel; - if (nEndingA >= 0) - nEndingA--; - int nEndingB = currentLevel->nextSecret; - if (nEndingB >= 0) - nEndingB--; - *pnEndingA = nEndingA; - *pnEndingB = nEndingB; -} - void levelEndLevel(int secret) { - int nEndingA, nEndingB; - auto episode = volfromlevelnum(currentLevel->levelNumber); gGameOptions.uGameFlags |= GF_AdvanceLevel; - levelGetNextLevels(&nEndingA, &nEndingB); - switch (secret) - { - case 0: - if (nEndingA == -1) - { - gGameOptions.uGameFlags |= GF_EndGame; - } - else - gNextLevel = nEndingA; - break; - case 1: - if (nEndingB == -1) - { - gGameOptions.uGameFlags |= GF_EndGame; - } - else - gNextLevel = nEndingB; - break; - } + if (!secret) gNextLevel = FindNextMap(currentLevel); + else gNextLevel = FindNextSecretMap(currentLevel); } void levelTryPlayMusic() diff --git a/source/games/blood/src/levels.h b/source/games/blood/src/levels.h index 6f72284bf..fdd0fc019 100644 --- a/source/games/blood/src/levels.h +++ b/source/games/blood/src/levels.h @@ -41,7 +41,6 @@ enum enum EGameFlag { GF_AdvanceLevel = 1, - GF_EndGame = 2, // 4 was for playing intro cutscenes but is no longer used. GF_PlayCutscene = 8, }; @@ -72,7 +71,7 @@ extern GAMEOPTIONS gGameOptions; extern int gSkill; extern char BloodIniFile[]; extern bool bINIOverride; -extern int gNextLevel; +extern MapRecord* gNextLevel; extern bool gGameStarted; void levelInitINI(const char *pzIni); diff --git a/source/games/blood/src/loadsave.cpp b/source/games/blood/src/loadsave.cpp index db6c86062..5cea9d695 100644 --- a/source/games/blood/src/loadsave.cpp +++ b/source/games/blood/src/loadsave.cpp @@ -641,7 +641,6 @@ void SerializeState(FSerializer& arc) ("modern", gModernMap) #endif ("cheating", bPlayerCheated) - ("nextlevel", gNextLevel) ("skyhoriz", pSky->horizfrac) ("skyy", pSky->yoffs) ("scale", pSky->yscale) diff --git a/source/games/blood/src/messages.cpp b/source/games/blood/src/messages.cpp index 42b92b344..8ff7ad3f7 100644 --- a/source/games/blood/src/messages.cpp +++ b/source/games/blood/src/messages.cpp @@ -268,7 +268,7 @@ static int parseArgs(char *pzArgs, int *nArg1, int *nArg2) if (!nArg1 || !nArg2 || strlen(pzArgs) < 3) return -1; *nArg1 = pzArgs[0] - '0'; - *nArg2 = (pzArgs[1] - '0')*10+(pzArgs[2]-'0') - 1; + *nArg2 = (pzArgs[1] - '0')*10+(pzArgs[2]-'0'); return 2; } @@ -421,7 +421,7 @@ static bool cheatMario(cheatseq_t* c) int nEpisode, nLevel; if (parseArgs((char*)c->Args, &nEpisode, &nLevel) == 2) { - auto map = FindMapByLevelNum(makelevelnum(nEpisode, nLevel)); + auto map = FindMapByIndex(nEpisode, nLevel); if (map) DeferedStartGame(map, -1); } return true; diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index a708623e0..9e5ef9fd0 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -5215,13 +5215,7 @@ void seqSpawnerOffSameTx(XSPRITE* pXSource) { void levelEndLevelCustom(int nLevel) { gGameOptions.uGameFlags |= GF_AdvanceLevel; - - if (nLevel >= 16 || nLevel < 0) { - gGameOptions.uGameFlags |= GF_EndGame; - return; - } - - gNextLevel = nLevel; + gNextLevel = FindMapByIndex(currentLevel->cluster, nLevel + 1); } void callbackUniMissileBurst(int nSprite) // 22 diff --git a/source/games/duke/src/cheats.cpp b/source/games/duke/src/cheats.cpp index 7dbce0077..c76f8c96e 100644 --- a/source/games/duke/src/cheats.cpp +++ b/source/games/duke/src/cheats.cpp @@ -292,11 +292,11 @@ static bool cheatItems(int player) static bool cheatLevel(cheatseq_t *s) { int volnume,levnume; - volnume = s->Args[0] - '0' - 1; - levnume = (s->Args[1] - '0')*10+(s->Args[2]-'0') - 1; + volnume = s->Args[0] - '0'; + levnume = (s->Args[1] - '0')*10+(s->Args[2]-'0'); // Instead of hard coded range checks on volume and level, let's just check if the level is defined. - auto map = FindMapByLevelNum(makelevelnum(volnume, levnume)); + auto map = FindMapByIndex(volnume, levnume); if (map) { ChangeLevel(map, -1);