From 4b064b9f3480fa6438a3f2b368e2b92099404819 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 May 2021 15:54:19 +0200 Subject: [PATCH] - migrated Exhumed's level setup to RMAPINFO. This game never had a proper setup so this also fixes the crashes with visiting the multiplayer maps. --- source/core/g_mapinfo.cpp | 37 +++ source/core/mapinfo.h | 10 + source/games/exhumed/src/2d.cpp | 5 +- source/games/exhumed/src/exhumed.cpp | 26 +- source/games/exhumed/src/exhumed.h | 2 +- source/games/exhumed/src/gameloop.cpp | 8 +- source/games/exhumed/src/init.cpp | 12 +- source/games/exhumed/src/items.cpp | 2 +- source/games/exhumed/src/move.cpp | 2 +- source/games/exhumed/src/object.cpp | 4 +- source/games/exhumed/src/player.cpp | 15 +- source/games/exhumed/src/ramses.cpp | 17 +- source/games/exhumed/src/save.cpp | 2 +- source/games/exhumed/src/sound.cpp | 2 +- source/games/exhumed/src/view.cpp | 5 +- .../static/filter/exhumed/engine/engine.def | 71 ---- .../static/filter/exhumed/engine/rmapinfo.txt | 306 ++++++++++++++++++ 17 files changed, 381 insertions(+), 145 deletions(-) delete mode 100644 wadsrc/static/filter/exhumed/engine/engine.def create mode 100644 wadsrc/static/filter/exhumed/engine/rmapinfo.txt diff --git a/source/core/g_mapinfo.cpp b/source/core/g_mapinfo.cpp index a0dadc7f8..5f6555819 100644 --- a/source/core/g_mapinfo.cpp +++ b/source/core/g_mapinfo.cpp @@ -557,6 +557,39 @@ DEFINE_MAP_OPTION(rr_mamaspawn, false) info->rr_mamaspawn = parse.sc.Number; } +DEFINE_MAP_OPTION(ex_ramses_horiz, false) +{ + parse.ParseAssign(); + parse.sc.MustGetNumber(); + info->ex_ramses_horiz = parse.sc.Number; +} + +DEFINE_MAP_OPTION(ex_ramses_cdtrack, false) +{ + parse.ParseAssign(); + parse.sc.MustGetNumber(); + info->ex_ramses_cdtrack = parse.sc.Number; +} + +DEFINE_MAP_OPTION(ex_ramses_pup, false) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + info->ex_ramses_pup = parse.sc.Number; +} + +DEFINE_MAP_OPTION(ex_ramses_text, false) +{ + parse.ParseAssign(); + parse.sc.MustGetString(); + info->ex_ramses_text = parse.sc.Number; +} + +int ex_ramses_horiz = 11; +int ex_ramses_cdtrack = -1; // this is not music, it is the actual dialogue! +FString ex_ramses_pup; +FString ex_ramses_text; + //========================================================================== // // All flag based map options @@ -592,6 +625,10 @@ MapFlagHandlers[] = { "forcenoeog", MITYPE_SETFLAG, LEVEL_FORCENOEOG, 0, -1 }, { "rrra_hulkspawn", MITYPE_SETFLAGG,LEVEL_RR_HULKSPAWN, 0, GAMEFLAG_RRRA }, { "rr_clearmoonshine", MITYPE_SETFLAGG,LEVEL_RR_CLEARMOONSHINE, 0, GAMEFLAG_RR }, + { "ex_training", MITYPE_SETFLAGG,LEVEL_EX_TRAINING, 0, GAMEFLAG_PSEXHUMED }, + { "ex_altsound", MITYPE_SETFLAGG,LEVEL_EX_ALTSOUND, 0, GAMEFLAG_PSEXHUMED }, + { "ex_countdown", MITYPE_SETFLAGG,LEVEL_EX_COUNTDOWN, 0, GAMEFLAG_PSEXHUMED }, + { "ex_multi", MITYPE_SETFLAGG,LEVEL_EX_MULTI, 0, GAMEFLAG_PSEXHUMED }, { NULL, MITYPE_IGNORE, 0, 0} }; diff --git a/source/core/mapinfo.h b/source/core/mapinfo.h index cce27cf8c..4d7d2e0b0 100644 --- a/source/core/mapinfo.h +++ b/source/core/mapinfo.h @@ -36,6 +36,12 @@ enum EMapGameFlags { LEVEL_RR_HULKSPAWN = 1, LEVEL_RR_CLEARMOONSHINE = 2, + + LEVEL_EX_COUNTDOWN = 4, + LEVEL_EX_TRAINING = 8, + LEVEL_EX_ALTSOUND = 16, + LEVEL_EX_MULTI = 32, + }; // These get filled in by the map definition parsers of the front ends. @@ -151,6 +157,10 @@ struct MapRecord // game specific stuff int rr_startsound = 0; int rr_mamaspawn = 15; + int ex_ramses_horiz = 11; + int ex_ramses_cdtrack = -1; // this is not music, it is the actual dialogue! + FString ex_ramses_pup; + FString ex_ramses_text; const char* LabelName() const { diff --git a/source/games/exhumed/src/2d.cpp b/source/games/exhumed/src/2d.cpp index 56966552a..ee08f3d0b 100644 --- a/source/games/exhumed/src/2d.cpp +++ b/source/games/exhumed/src/2d.cpp @@ -410,10 +410,9 @@ void TextOverlay::ComputeCinemaText() nHeight = screentext.Size() * 10; } -void TextOverlay::ReadyCinemaText(uint16_t nVal) +void TextOverlay::ReadyCinemaText(const char* nVal) { - FStringf label("TXT_EX_CINEMA%d", nVal); - label = GStrings(label); + FString label = nVal[0] == '$'? GStrings(nVal +1) : nVal; screentext = label.Split("\n"); ComputeCinemaText(); } diff --git a/source/games/exhumed/src/exhumed.cpp b/source/games/exhumed/src/exhumed.cpp index 24f64b325..d8117e48b 100644 --- a/source/games/exhumed/src/exhumed.cpp +++ b/source/games/exhumed/src/exhumed.cpp @@ -262,7 +262,7 @@ void GameMove(void) sprite[i].backuploc(); } - if (currentLevel->levelNumber == kMap20) + if (currentLevel->gameflags & LEVEL_EX_COUNTDOWN) { if (lCountDown <= 0) { @@ -471,7 +471,7 @@ void GameInterface::Ticker() void LevelFinished() { - NextMap = currentLevel->levelNumber == 20 ? nullptr : FindMapByLevelNum(currentLevel->levelNumber + 1); // todo: Use the map record for progression + NextMap = FindNextMap(currentLevel); EndLevel = 13; } @@ -496,26 +496,6 @@ void GameInterface::app_init() help_disabled = true; #endif - auto vol0 = MustFindVolume(0); - auto vol1 = MustFindVolume(1); - if (vol0) vol0->startmap = "LEV1"; - if (vol1) vol1->startmap = "LEV0"; - - // Create the global level table. Parts of the engine need it, even though the game itself does not. - for (int i = 0; i <= 32; i++) - { - auto mi = AllocateMap(); - mi->fileName.Format("LEV%d.MAP", i); - mi->labelName.Format("LEV%d", i); - mi->name.Format("$TXT_EX_MAP%02d", i); - mi->levelNumber = i; - mi->cluster = i? 1 : 2; // training is cluster 2 - - int nTrack = i; - if (nTrack != 0) nTrack--; - mi->cdSongId = (nTrack % 8) + 11; - } - InitCheats(); registerosdcommands(); if (nNetPlayerCount == -1) @@ -637,7 +617,7 @@ void SerializeState(FSerializer& arc) int loaded = 0; if (arc.BeginObject("state")) { - if (arc.isReading() && currentLevel->levelNumber == 20) + if (arc.isReading() && (currentLevel->gameflags & LEVEL_EX_COUNTDOWN)) { InitEnergyTile(); } diff --git a/source/games/exhumed/src/exhumed.h b/source/games/exhumed/src/exhumed.h index 110149ff5..59e1e1a52 100644 --- a/source/games/exhumed/src/exhumed.h +++ b/source/games/exhumed/src/exhumed.h @@ -188,7 +188,7 @@ public: void Start(double starttime); void ComputeCinemaText(); - void ReadyCinemaText(uint16_t nVal); + void ReadyCinemaText(const char* nVal); void DisplayText(); bool AdvanceCinemaText(double clock); void SetPalette(int pal) { currentCinemaPalette = pal; } diff --git a/source/games/exhumed/src/gameloop.cpp b/source/games/exhumed/src/gameloop.cpp index c8276456a..ab08b2721 100644 --- a/source/games/exhumed/src/gameloop.cpp +++ b/source/games/exhumed/src/gameloop.cpp @@ -69,7 +69,7 @@ void GameInterface::Render() drawtime.Reset(); drawtime.Clock(); - if (currentLevel && currentLevel->levelNumber == kMap20) + if (currentLevel && (currentLevel->gameflags & LEVEL_EX_COUNTDOWN)) { DoEnergyTile(); DrawClock(); @@ -153,7 +153,7 @@ DEFINE_ACTION_FUNCTION(DMapScreen, SetNextLevel) void GameInterface::LevelCompleted(MapRecord *to_map, int skill) { Mus_Stop(); - if (currentLevel->levelNumber == 0) + if (currentLevel->gameflags & LEVEL_EX_TRAINING) { gameaction = ga_mainmenu; return; @@ -168,8 +168,8 @@ void GameInterface::LevelCompleted(MapRecord *to_map, int skill) { if (to_map->levelNumber > nBestLevel) nBestLevel = to_map->levelNumber - 1; - if (to_map->levelNumber == 20) nPlayerLives[0] = 0; - if (to_map->levelNumber == 0) // skip all intermission stuff when going to the training map. + if (to_map->gameflags & LEVEL_EX_COUNTDOWN) nPlayerLives[0] = 0; + if (to_map->gameflags & LEVEL_EX_TRAINING) { gameaction = ga_nextlevel; return; diff --git a/source/games/exhumed/src/init.cpp b/source/games/exhumed/src/init.cpp index 8645a05ac..5c2c1db7c 100644 --- a/source/games/exhumed/src/init.cpp +++ b/source/games/exhumed/src/init.cpp @@ -68,7 +68,7 @@ uint8_t bIsVersion6 = true; uint8_t LoadLevel(MapRecord* map) { - if (map->levelNumber == kMap20) + if (map->gameflags & LEVEL_EX_COUNTDOWN) { lCountDown = 81000; nAlarmTicks = 30; @@ -116,12 +116,12 @@ uint8_t LoadLevel(MapRecord* map) InitItems(); InitInput(); - if (map->levelNumber == kMap20) { + if (map->gameflags & LEVEL_EX_COUNTDOWN) { InitEnergyTile(); } } - if (map->levelNumber > 15) + if (map->gameflags & LEVEL_EX_ALTSOUND) { nSwitchSound = 35; nStoneSound = 23; @@ -196,10 +196,8 @@ void InitLevel(MapRecord* map) RefreshStatus(); - int nTrack = map->levelNumber; - if (nTrack != 0) nTrack--; - - playCDtrack((nTrack % 8) + 11, true); + if (!mus_redbook && map->music.IsNotEmpty()) Mus_Play(map->labelName, map->music, true); // Allow non-CD music if defined for the current level + playCDtrack(map->cdSongId, true); setLevelStarted(currentLevel); } diff --git a/source/games/exhumed/src/items.cpp b/source/games/exhumed/src/items.cpp index edcd344f6..25b2bb945 100644 --- a/source/games/exhumed/src/items.cpp +++ b/source/games/exhumed/src/items.cpp @@ -432,7 +432,7 @@ void StartRegenerate(short nSprite) pSprite->extra = 1350; pSprite->ang = nFirstRegenerate; - if (currentLevel->levelNumber <= kMap20) + if (!(currentLevel->gameflags & LEVEL_EX_MULTI)) { pSprite->ang /= 5; } diff --git a/source/games/exhumed/src/move.cpp b/source/games/exhumed/src/move.cpp index 7a7ab0c94..fdd31dede 100644 --- a/source/games/exhumed/src/move.cpp +++ b/source/games/exhumed/src/move.cpp @@ -207,7 +207,7 @@ void MoveThings() DoMovingSects(); DoRegenerates(); - if (currentLevel->levelNumber == kMap20) + if (currentLevel->gameflags & LEVEL_EX_COUNTDOWN) { DoFinale(); if (lCountDown < 1800 && nDronePitch < 2400 && !lFinaleStart) diff --git a/source/games/exhumed/src/object.cpp b/source/games/exhumed/src/object.cpp index 69701a94e..b73c04415 100644 --- a/source/games/exhumed/src/object.cpp +++ b/source/games/exhumed/src/object.cpp @@ -2254,7 +2254,7 @@ FUNCOBJECT_GOTO: } } - if (currentLevel->levelNumber <= 20 || nStat != kStatExplodeTrigger) + if (!(currentLevel->gameflags & LEVEL_EX_MULTI) || nStat != kStatExplodeTrigger) { runlist_SubRunRec(sprite[nSprite].owner); runlist_SubRunRec(ObjectList[nObject].field_4); @@ -2689,7 +2689,7 @@ void PostProcess() } } - if (currentLevel->levelNumber != kMap20) + if (!(currentLevel->gameflags & LEVEL_EX_COUNTDOWN)) { // esi is i for (i = 0; i < numsectors; i++) diff --git a/source/games/exhumed/src/player.cpp b/source/games/exhumed/src/player.cpp index 1f02a17f3..433a27bc5 100644 --- a/source/games/exhumed/src/player.cpp +++ b/source/games/exhumed/src/player.cpp @@ -417,7 +417,7 @@ void RestartPlayer(short nPlayer) plr->nAir = 100; airpages = 0; - if (currentLevel->levelNumber <= kMap20) + if (!(currentLevel->gameflags & LEVEL_EX_MULTI)) { RestoreMinAmmo(nPlayer); } @@ -570,7 +570,7 @@ void StartDeathSeq(int nPlayer, int nVal) BuildStatusAnim((3 * (nLives - 1)) + 7, 0); } - if (currentLevel->levelNumber > 0) { // if not on the training level + if (!(currentLevel->gameflags & LEVEL_EX_TRAINING)) { // if not on the training level nPlayerLives[nPlayer]--; } @@ -679,7 +679,7 @@ void FuncPlayer(int a, int nDamage, int nRun) { int var_48 = 0; int var_40; - bool mplevel = currentLevel->levelNumber > 20; + bool mplevel = (currentLevel->gameflags & LEVEL_EX_MULTI); short nPlayer = RunData[nRun].nVal; assert(nPlayer >= 0 && nPlayer < kMaxPlayers); @@ -1033,14 +1033,7 @@ void FuncPlayer(int a, int nDamage, int nRun) InitSpiritHead(); PlayerList[nPlayer].nDestVertPan = q16horiz(0); - if (currentLevel->levelNumber == 11) - { - PlayerList[nPlayer].horizon.settarget(46); - } - else - { - PlayerList[nPlayer].horizon.settarget(11); - } + PlayerList[nPlayer].horizon.settarget(currentLevel->ex_ramses_horiz); } } else diff --git a/source/games/exhumed/src/ramses.cpp b/source/games/exhumed/src/ramses.cpp index 546acfcf2..404e9e281 100644 --- a/source/games/exhumed/src/ramses.cpp +++ b/source/games/exhumed/src/ramses.cpp @@ -64,8 +64,6 @@ short nTalkTime = 0; void InitSpiritHead() { - char filename[20]; - nPixels = 0; nSpiritRepeatX = sprite[nSpiritSprite].xrepeat; @@ -137,26 +135,15 @@ void InitSpiritHead() fadecdaudio(); - int nTrack; - - if (currentLevel->levelNumber == 1) - { - nTrack = 3; - } - else - { - nTrack = 7; - } - + int nTrack = currentLevel->ex_ramses_cdtrack; playCDtrack(nTrack, false); StartSwirlies(); - sprintf(filename, "LEV%d.PUP", currentLevel->levelNumber); lNextStateChange = PlayClock; lHeadStartClock = PlayClock; - auto headfd = fileSystem.OpenFileReader(filename); + auto headfd = fileSystem.OpenFileReader(currentLevel->ex_ramses_pup); if (!headfd.isOpen()) { memset(cPupData, 0, sizeof(cPupData)); diff --git a/source/games/exhumed/src/save.cpp b/source/games/exhumed/src/save.cpp index 61976e148..8046808f6 100644 --- a/source/games/exhumed/src/save.cpp +++ b/source/games/exhumed/src/save.cpp @@ -117,7 +117,7 @@ void GameInterface::SerializeGameState(FSerializer& arc) parallaxtype = 2; g_visibility = 1024; - if (currentLevel->levelNumber > 15) + if (currentLevel->gameflags & LEVEL_EX_ALTSOUND) { nSwitchSound = 35; nStoneSound = 23; diff --git a/source/games/exhumed/src/sound.cpp b/source/games/exhumed/src/sound.cpp index d9d35005f..5f80bf79c 100644 --- a/source/games/exhumed/src/sound.cpp +++ b/source/games/exhumed/src/sound.cpp @@ -724,7 +724,7 @@ void CheckAmbience(short nSector) void UpdateCreepySounds() { - if (currentLevel->levelNumber == 20 || nFreeze || !SoundEnabled()) + if ((currentLevel->gameflags & LEVEL_EX_COUNTDOWN) || nFreeze || !SoundEnabled()) return; spritetype* pSprite = &sprite[PlayerList[nLocalPlayer].nSprite]; nCreepyTimer--; diff --git a/source/games/exhumed/src/view.cpp b/source/games/exhumed/src/view.cpp index 485a783d8..348e44205 100644 --- a/source/games/exhumed/src/view.cpp +++ b/source/games/exhumed/src/view.cpp @@ -402,10 +402,7 @@ void DrawView(double smoothRatio, bool sceneonly) if (bSubTitles) { subtitleOverlay.Start(I_GetTimeNS() * (120. / 1'000'000'000)); - if (currentLevel->levelNumber == 1) - subtitleOverlay.ReadyCinemaText(1); - else - subtitleOverlay.ReadyCinemaText(5); + subtitleOverlay.ReadyCinemaText(currentLevel->ex_ramses_text); } inputState.ClearAllInput(); } diff --git a/wadsrc/static/filter/exhumed/engine/engine.def b/wadsrc/static/filter/exhumed/engine/engine.def deleted file mode 100644 index 42a6265ef..000000000 --- a/wadsrc/static/filter/exhumed/engine/engine.def +++ /dev/null @@ -1,71 +0,0 @@ -// Cutscene definitions for Duke - -definecutscene intro -{ - function ExhumedCutscenes.BuildIntro -} - -definecutscene map lev5 -{ - intro - { - function ExhumedCutscenes.BuildCinemaBefore5 - } -} - -definecutscene map lev10 -{ - outro - { - function ExhumedCutscenes.BuildCinemaAfter10 - } -} - -definecutscene map lev11 -{ - intro - { - function ExhumedCutscenes.BuildCinemaBefore11 - } -} - -definecutscene map lev15 -{ - outro - { - function ExhumedCutscenes.BuildCinemaAfter15 - } -} - -definecutscene map lev20 -{ - intro - { - function ExhumedCutscenes.BuildCinemaBefore20 - } - outro - { - function ExhumedCutscenes.BuildCinemaAfter20 - } -} - -/* -definecutscene gameover -{ - function ExhumedCutscenes.BuildGameoverScene -} - -definecutscene lose -{ - function ExhumedCutscenes.BuildCinemaLose -} - -definecutscene loading -{ - function DukeCutscenes.BuildLoading -} -*/ - -definecutscene summary ExhumedCutscenes.BuildMap -//definecutscene mpsummary DukeCutscenes.BuildMPSummary - diff --git a/wadsrc/static/filter/exhumed/engine/rmapinfo.txt b/wadsrc/static/filter/exhumed/engine/rmapinfo.txt new file mode 100644 index 000000000..5fafd97b6 --- /dev/null +++ b/wadsrc/static/filter/exhumed/engine/rmapinfo.txt @@ -0,0 +1,306 @@ + +episode LEV1 +{ + name = "Exhumed" + noskillmenu +} + +episode LEV0 +{ + name = "$TXT_EX_MAP00" + noskillmenu +} + +cluster 1 +{ + name = "Exhumed" + gameover + { + function = ExhumedCutscenes.BuildGameoverScene + } +} + +cluster 2 +{ + name = "$TXT_EX_MAP00" +} + +cluster 3 +{ + name = "Multiplayer" +} + +cluster 4 +{ + gameover + { + function = ExhumedCutscenes.BuildCinemaLose + } +} + +map lev0 "$TXT_EX_MAP00" +{ + cdtrack = 11 + ex_training + cluster = 2 +} + +map lev1 "$TXT_EX_MAP01" +{ + cdtrack = 11 + cluster = 1 + ex_ramses_cdtrack = 3 + ex_ramses_pup = "lev1.pup" + ex_ramses_text = "$TXT_EX_CINEMA1" +} + +map lev2 "$TXT_EX_MAP02" +{ + cdtrack = 12 + cluster = 1 +} + +map lev3 "$TXT_EX_MAP03" +{ + cdtrack = 13 + cluster = 1 +} + +map lev4 "$TXT_EX_MAP04" +{ + cdtrack = 14 + cluster = 1 +} + +map lev5 "$TXT_EX_MAP05" +{ + cdtrack = 15 + cluster = 1 + intro + { + function = ExhumedCutscenes.BuildCinemaBefore5 + } +} + +map lev6 "$TXT_EX_MAP06" +{ + cdtrack = 16 + cluster = 1 +} + +map lev7 "$TXT_EX_MAP07" +{ + cdtrack = 17 + cluster = 1 +} + +map lev8 "$TXT_EX_MAP08" +{ + cdtrack = 18 + cluster = 1 +} + +map lev9 "$TXT_EX_MAP09" +{ + cdtrack = 11 + cluster = 1 +} + +map lev10 "$TXT_EX_MAP10" +{ + cdtrack = 12 + cluster = 1 + outro + { + function = ExhumedCutscenes.BuildCinemaAfter10 + } +} + +map lev11 "$TXT_EX_MAP11" +{ + cdtrack = 13 + cluster = 1 + ex_ramses_cdtrack = 7 + ex_ramses_pup = "lev11.pup" + ex_ramses_text = "$TXT_EX_CINEMA5" + ex_ramses_horiz = 46 + intro + { + function = ExhumedCutscenes.BuildCinemaBefore11 + } +} + +map lev12 "$TXT_EX_MAP12" +{ + cdtrack = 14 + cluster = 1 +} + +map lev13 "$TXT_EX_MAP13" +{ + cdtrack = 15 + cluster = 1 +} + +map lev14 "$TXT_EX_MAP14" +{ + cdtrack = 16 + cluster = 1 +} + +map lev15 "$TXT_EX_MAP15" +{ + cdtrack = 17 + cluster = 1 + outro + { + function = ExhumedCutscenes.BuildCinemaAfter15 + } +} + +map lev16 "$TXT_EX_MAP16" +{ + cdtrack = 18 + cluster = 1 + ex_altsound +} + +map lev17 "$TXT_EX_MAP17" +{ + cdtrack = 11 + cluster = 1 + ex_altsound +} + +map lev18 "$TXT_EX_MAP18" +{ + cdtrack = 12 + cluster = 1 + ex_altsound +} + +map lev19 "$TXT_EX_MAP19" +{ + cdtrack = 13 + cluster = 1 + ex_altsound +} + +map lev20 "$TXT_EX_MAP20" +{ + cdtrack = 14 + cluster = 4 + next = "-" + ex_altsound + ex_countdown + intro + { + function = ExhumedCutscenes.BuildCinemaBefore20 + } + outro + { + function = ExhumedCutscenes.BuildCinemaAfter20 + } +} + +map lev21 "$TXT_EX_MAP21" +{ + cdtrack = 15 + cluster = 3 + ex_multi +} + +map lev22 "$TXT_EX_MAP22" +{ + cdtrack = 16 + cluster = 3 + ex_multi +} + +map lev23 "$TXT_EX_MAP23" +{ + cdtrack = 17 + cluster = 3 + ex_multi +} + +map lev24 "$TXT_EX_MAP24" +{ + cdtrack = 18 + cluster = 3 + ex_multi +} + +map lev25 "$TXT_EX_MAP25" +{ + cdtrack = 11 + cluster = 3 + ex_multi +} + +map lev26 "$TXT_EX_MAP26" +{ + cdtrack = 12 + cluster = 3 + ex_multi +} + +map lev27 "$TXT_EX_MAP27" +{ + cdtrack = 13 + cluster = 3 + ex_multi +} + +map lev28 "$TXT_EX_MAP28" +{ + cdtrack = 14 + cluster = 3 + ex_multi +} + +map lev29 "$TXT_EX_MAP29" +{ + cdtrack = 15 + cluster = 3 + ex_multi +} + +map lev30 "$TXT_EX_MAP30" +{ + cdtrack = 16 + cluster = 3 + ex_multi +} + +map lev31 "$TXT_EX_MAP31" +{ + cdtrack = 17 + cluster = 3 + ex_multi +} + +map lev32 "$TXT_EX_MAP32" +{ + cdtrack = 18 + cluster = 3 + ex_multi +} + +cutscenes +{ + intro + { + function = ExhumedCutscenes.BuildIntro + } + + loadscreen + { + function = DukeCutscenes.BuildLoading + } +} + +gameinfo +{ + summaryscreen = ExhumedCutscenes.BuildMap +}