diff --git a/source/exhumed/src/2d.cpp b/source/exhumed/src/2d.cpp
index 40f490918..896ba6ac8 100644
--- a/source/exhumed/src/2d.cpp
+++ b/source/exhumed/src/2d.cpp
@@ -47,24 +47,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 BEGIN_PS_NS
 
-int SyncScreenJob()
-{
-    while (gamestate == GS_INTERMISSION || gamestate == GS_INTRO)
-    {
-        UpdateSounds();
-        HandleAsync();
-        updatePauseStatus();
-        D_ProcessEvents();
-        ControlInfo info;
-        CONTROL_GetInput(&info);
-        C_RunDelayedCommands();
-
-        RunScreenJobFrame();	// This handles continuation through its completion callback.
-        videoNextPage();
-    }
-    return 0;
-}
-
+int selectedlevelnew;
 
 //---------------------------------------------------------------------------
 //
@@ -628,8 +611,6 @@ void DoTitle(CompletionFunc completion)
 	 0, {{1, 20,  10}, {1, 20,   10}, {1, 20,   10}}
  };
 
-static int gLevelNew; // this is needed to get the chosen level out of the map screen class
-
 class DMapScreen : public DScreenJob
 {
 	int i;
@@ -770,7 +751,7 @@ public:
 			
 			nIdleSeconds = 0;
 		}
-		gLevelNew = nLevelNew;
+		selectedlevelnew = nLevelNew + 1;
 		return skiprequest? -1 : nIdleSeconds < 12? 1 : 0;
 	}
 
@@ -826,11 +807,10 @@ public:
 	}
 };
 
- void menu_DrawTheMap(int nLevel, int nLevelNew, int nLevelBest, std::function<void(int)> completion)
+ void menu_DrawTheMap(int nLevel, int nLevelNew, int nLevelBest, TArray<JobDesc> &jobs)
  {
 	 if (nLevel > kMap20 || nLevelNew > kMap20) // max single player levels
 	 {
-		 completion(-1);
 		 return;
 	 }
      nLevelBest = kMap20;
@@ -838,14 +818,8 @@ public:
 	 if (nLevel < 1) nLevel = 1;
 	 if (nLevelNew < 1) nLevelNew = nLevel;
 	 
-	  auto mycompletion = [=](bool)
-	  {
-		  completion(gLevelNew+1);
-	  };
-	  // 0-offset the level numbers
-	 gLevelNew = nLevelNew;
-	 JobDesc job = { Create<DMapScreen>(nLevel-1, nLevelNew-1, nLevelBest-1) };
-	 RunScreenJob(&job, 1, mycompletion);
+     // 0-offset the level numbers
+     jobs.Push( { Create<DMapScreen>(nLevel-1, nLevelNew-1, nLevelBest-1) });
  }
 
 //---------------------------------------------------------------------------
@@ -937,8 +911,6 @@ static const char * const cinpalfname[] = {
     "terror.pal"
 };
 
-extern short nCinemaSeen[30];
-
 void uploadCinemaPalettes()
 {
     for (int i = 0; i < countof(cinpalfname); i++)
@@ -965,9 +937,10 @@ class DCinema : public DScreenJob
 	short cinematile;
 	int currentCinemaPalette;
     int edx;
+    int check;
 
 public:
-	DCinema(int nVal) : DScreenJob(fadein|fadeout)
+	DCinema(int nVal, int checklevel = -1) : DScreenJob(fadein|fadeout)
 	{
 		static const short cinematiles[] = { 3454, 3452, 3449, 3445, 3451, 3448, 3446};
         static const int8_t bxvals[] = { 4, 0, 2, 7, 3, 8, 6 };
@@ -979,6 +952,7 @@ public:
         edx = dxvals[nVal - 1];
         text.Start(0);
         text.ReadyCinemaText(bxvals[nVal - 1]);
+        check = checklevel;
     }
 	
     int Frame(uint64_t clock, bool skiprequest) override
@@ -986,6 +960,7 @@ public:
 
         if (clock == 0)
         {
+            if (check > 0 && check != selectedlevelnew) return 0; // immediately abort if the player selected a different level on the map
             StopAllSounds();
             if (edx != -1)
             {
@@ -1280,15 +1255,43 @@ private:
     }
 };
 
+//---------------------------------------------------------------------------
+//
+// player died
+//
+//---------------------------------------------------------------------------
 
-
-// temporary.
-void RunCinemaScene(int num)
+void DoGameOverScene(bool finallevel)
 {
-    JobDesc job = { num == -1? (DScreenJob*)Create<DExCredits>() : Create<DCinema>(num) };
-    RunScreenJob(&job, 1, [](bool) { gamestate = GS_LEVEL; });
-    SyncScreenJob();
+    JobDesc job;
+
+    if (finallevel)
+    {
+        playCDtrack(9, false);
+        //FadeToWhite();
+        job = { Create<DCinema>(4) };
+    }
+    else
+    {
+        StopCD();
+        PlayGameOverSound();
+        job = { Create<DImageScreen>(tileGetTexture(kTile3591), DScreenJob::fadein | DScreenJob::fadeout, 0x7fffffff) };
+    }
+    RunScreenJob(&job, 1, [](bool) { gamestate = GS_STARTUP; });
 }
 
 
+void DoAfterCinemaScene(int nLevel, TArray<JobDesc>& jobs)
+{
+    static const uint8_t nAfterScene[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 7, 0, 0, 0, 0, 6 };
+    if (nAfterScene[nLevel]) jobs.Push({ Create<DCinema>(nAfterScene[nLevel]) });
+    if (nLevel == 20) jobs.Push({ Create<DExCredits>() });
+}
+
+void DoBeforeCinemaScene(int nLevel, TArray<JobDesc>& jobs)
+{
+    if (nLevel == 5) jobs.Push({ Create<DCinema>(3) });
+    else if (nLevel == 11) jobs.Push({ Create<DCinema>(1, 11) });
+}
+
 END_PS_NS
diff --git a/source/exhumed/src/bubbles.cpp b/source/exhumed/src/bubbles.cpp
index d6cc1bc63..2fefeaffc 100644
--- a/source/exhumed/src/bubbles.cpp
+++ b/source/exhumed/src/bubbles.cpp
@@ -219,7 +219,7 @@ void DoBubbleMachines()
 void BuildBubbleMachine(int nSprite)
 {
     if (nMachineCount >= kMaxMachines) {
-        I_Error("too many bubble machines in level %d\n", levelnew);
+        I_Error("too many bubble machines in level %d\n", levelnum);
         exit(-1);
     }
 
diff --git a/source/exhumed/src/d_menu.cpp b/source/exhumed/src/d_menu.cpp
index 8ea967bd1..4ad5c9fe7 100644
--- a/source/exhumed/src/d_menu.cpp
+++ b/source/exhumed/src/d_menu.cpp
@@ -36,42 +36,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 BEGIN_PS_NS
 
-int handle1;
-
-
-int MenuExitCondition;
-
-int menu_Menu(int nVal)
-{
-	MenuExitCondition = -2;
-	M_StartControlPanel(false);
-	M_SetMenu(NAME_Mainmenu);
-	while (M_Active())
-	{
-		auto nLogoTile = EXHUMED ? kExhumedLogo : kPowerslaveLogo;
-		int dword_9AB5F = ((int)totalclock / 16) & 3;
-
-		twod->ClearScreen();
-
-		DrawRel(kSkullHead, 160, 100, 32);
-		DrawRel(kSkullJaw, 161, 130, 32);
-		DrawRel(nLogoTile, 160, 40, 32);
-
-		// draw the fire urn/lamp thingies
-		DrawRel(kTile3512 + dword_9AB5F, 50, 150, 32);
-		DrawRel(kTile3512 + ((dword_9AB5F + 2) & 3), 270, 150, 32);
-
-		HandleAsync();
-		D_ProcessEvents();
-		videoNextPage();
-
-	}
-	int me = MenuExitCondition;
-	MenuExitCondition = -2;
-	return me;
-}
-
-
 //----------------------------------------------------------------------------
 //
 // Implements the native looking menu used for the main menu
@@ -187,7 +151,7 @@ void GameInterface::MenuClosed()
 
 void GameInterface::StartGame(FNewGameStartup& gs)
 {
-	MenuExitCondition = gs.Episode;	// Gross hack. The main loop needs to be redone for better handling.
+	GameAction = gs.Episode;	// 0 is training, 1 is the regular game
 }
 
 FSavegameInfo GameInterface::GetSaveSig()
diff --git a/source/exhumed/src/engine.h b/source/exhumed/src/engine.h
index 52d97f7e1..6702122a1 100644
--- a/source/exhumed/src/engine.h
+++ b/source/exhumed/src/engine.h
@@ -95,7 +95,6 @@ int LoadPaletteLookups();
 void SetGreenPal();
 void RestoreGreenPal();
 void FixPalette();
-void FadeToWhite();
 int HavePLURemap();
 uint8_t RemapPLU(uint8_t pal);
 
diff --git a/source/exhumed/src/exhumed.cpp b/source/exhumed/src/exhumed.cpp
index 35c935b36..f8490e8a2 100644
--- a/source/exhumed/src/exhumed.cpp
+++ b/source/exhumed/src/exhumed.cpp
@@ -61,7 +61,7 @@ int32_t registerosdcommands(void);
 void InitFonts();
 
 int htimer = 0;
-bool EndLevel = false;
+int EndLevel = false;
 
 
 PlayerInput localInput;
@@ -112,7 +112,6 @@ void EraseScreen(int nVal);
 void LoadStatus();
 void MySetView(int x1, int y1, int x2, int y2);
 void mysetbrightness(char al);
-void FadeIn();
 
 char sHollyStr[40];
 
@@ -127,7 +126,6 @@ short nFreeze;
 short nSnakeCam = -1;
 
 short nLocalSpr;
-short levelnew = 1;
 
 int nNetPlayerCount = 0;
 
@@ -146,7 +144,6 @@ short nEnergyTowers = 0;
 
 short nCfgNetPlayers = 0;
 FILE *vcrfp = NULL;
-short forcelevel = -1;
 
 int lLocalButtons = 0;
 int lLocalCodes = 0;
@@ -234,10 +231,8 @@ void timerhandler()
     }
 }
 
-extern int MenuExitCondition;
 void HandleAsync()
 {
-    MenuExitCondition = -2;
     handleevents();
 
 }
@@ -388,15 +383,6 @@ void DoRedAlert(int nVal)
     }
 }
 
-void LockEnergyTiles()
-{
-    // old	loadtilelockmode = 1;
-    tileLoad(kTile3603);
-    tileLoad(kEnergy1);
-    tileLoad(kEnergy2);
-    // old  loadtilelockmode = 0;
-}
-
 void DrawClock()
 {
     int ebp = 49;
@@ -474,13 +460,7 @@ void GameMove(void)
     {
         if (lCountDown <= 0)
         {
-            for (int i = 0; i < nTotalPlayers; i++) {
-                nPlayerLives[i] = 0;
-            }
-
-            DoFailedFinalScene();
-            levelnew = 100;
-
+            DoGameOverScene(true);
             return;
         }
         // Pink section
@@ -578,11 +558,6 @@ void GameTicker()
         if (nPlayerLives[nLocalPlayer] <= 0) {
             startmainmenu();
         }
-#if 0
-        if (!bInDemo && levelnew > nBestLevel && levelnew != 0 && levelnew <= kMap20 && SavePosition > -1) {
-            menu_GameSave(SavePosition);
-        }
-#endif
     }
     bInMove = false;
 
@@ -669,7 +644,6 @@ void InitGame()
     int i;
     //int esi = 1;
     //int edi = esi;
-    levelnew = 1;
 
     buttonMap.SetButtons(actions, NUM_ACTIONS);
 
@@ -677,20 +651,17 @@ void InitGame()
     // 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 = &mapList[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;
 
         int nTrack = i;
         if (nTrack != 0) nTrack--;
         mi->cdSongId = (nTrack % 8) + 11;
     }
 
-    if (nNetPlayerCount && forcelevel == -1) {
-        forcelevel = 1;
-    }
-
     SetCheats(excheats, countof(excheats));
     registerosdcommands();
 
@@ -812,7 +783,6 @@ static SavegameHelper sgh("exhumed",
     SV(nFreeze),
     SV(nSnakeCam),
     SV(nLocalSpr),
-    SV(levelnew),
     SV(nClockVal),  // kTile3603
     SV(nRedTicks),
     SV(nAlarmTicks),
diff --git a/source/exhumed/src/exhumed.h b/source/exhumed/src/exhumed.h
index 236b461a2..213830a07 100644
--- a/source/exhumed/src/exhumed.h
+++ b/source/exhumed/src/exhumed.h
@@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #include "tarray.h"
 #include "zstring.h"
 #include "filesystem.h"
+#include "screenjob.h"
 
 BEGIN_PS_NS
 
@@ -110,14 +111,15 @@ void ShutDown(void);
 void DebugOut(const char *fmt, ...);
 int ExhumedMain(int argc, char *argv[]);
 
-void FinishLevel();
 void ResetEngine();
 
 void SetHiRes();
 
 void BlackOut();
 
-void DoGameOverScene();
+void DoGameOverScene(bool finallevel);
+void DoAfterCinemaScene(int nLevel, TArray<JobDesc> &jobs);
+void DoBeforeCinemaScene(int nLevel, TArray<JobDesc>& jobs);
 
 int Query(short n, short l, ...);
 
@@ -129,11 +131,6 @@ void TintPalette(int a, int b, int c);
 
 void EraseScreen(int eax);
 
-void RestorePalette();
-
-void FadeIn();
-void FadeOut(int bFadeMusic);
-
 void mychangespritesect(int nSprite, int nSector);
 void mydeletesprite(int nSprite);
 
@@ -142,7 +139,6 @@ void GrabPalette();
 void mysetbrightness(char nBrightness);
 
 void StartFadeIn();
-int DoFadeIn();
 
 void InitSpiritHead();
 
@@ -160,11 +156,13 @@ void InitGame();
 void InitNewGame();
 void startmainmenu();
 
-extern bool EndLevel;
+extern int EndLevel;
 extern int32_t g_commandSetup;
 extern int32_t g_noSetup;
 
 extern char sHollyStr[];
+extern int selectedlevelnew;
+extern int GameAction;
 
 extern int localclock;
 
@@ -200,6 +198,7 @@ extern short nCurBodyNum;
 extern short nBodyTotal;
 
 extern short bSnakeCam;
+extern uint8_t nCinemaSeen;
 
 extern short levelnum;
 //extern short nScreenWidth;
@@ -216,7 +215,6 @@ extern short lastfps;
 extern int flash;
 
 extern short nLocalSpr;
-extern short levelnew;
 
 extern short nSnakeCam;
 
diff --git a/source/exhumed/src/gameloop.cpp b/source/exhumed/src/gameloop.cpp
index 3049f43df..40d5ecf86 100644
--- a/source/exhumed/src/gameloop.cpp
+++ b/source/exhumed/src/gameloop.cpp
@@ -51,24 +51,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 BEGIN_PS_NS
 
 short nBestLevel;
-int forcelevel = -1;
 static int32_t nonsharedtimer;
 
-extern int MenuExitCondition;
+int GameAction;
 
-extern short nCinemaSeen[30];
+extern uint8_t nCinemaSeen;
 extern ClockTicks tclocks;
 
 void RunCinemaScene(int num);
 void GameMove(void);
 void InitGame();
-void LockEnergyTiles();
 void DrawClock();
 int32_t calc_smoothratio(ClockTicks totalclk, ClockTicks ototalclk);
-int SyncScreenJob();
 void DoTitle(CompletionFunc completion);
 
-void FinishLevel()
+int levelnew = -1;
+
+void FinishLevel(TArray<JobDesc> jobs)
 {
     if (levelnum > nBestLevel) {
         nBestLevel = levelnum - 1;
@@ -81,135 +80,38 @@ void FinishLevel()
     bCamera = false;
     nMapMode = 0;
 
-    if (levelnum != kMap20)
+    if (levelnum != kMap20 && EndLevel != 2)
     {
-        EraseScreen(4);
+        // There's really no choice but to enter an active wait loop here to make the sound play out.
         PlayLocalSound(StaticSound[59], 0, true, CHANF_UI);
-        videoNextPage();
-        //WaitTicks(12);
-        DrawView(65536);
-        videoNextPage();
+        int nTicks = totalclock + 12;
+        while (nTicks > (int)totalclock) { HandleAsync(); }
     }
+    else nPlayerLives[0] = 0;
 
-    FadeOut(1);
-    EraseScreen(overscanindex);
-
-    if (levelnum == 0)
-    {
-        nPlayerLives[0] = 0;
-        levelnew = 100;
-    }
-    else
-    {
-        DoAfterCinemaScene(levelnum);
-        if (levelnum == kMap20)
-        {
-            //DoCredits();
-            nPlayerLives[0] = 0;
-        }
-    }
+    DoAfterCinemaScene(levelnum, jobs);
 }
 
 
-
-
-short nBeforeScene[] = { 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-
-void CheckBeforeScene(int nLevel)
+void showmap(short nLevel, short nLevelNew, short nLevelBest, TArray<JobDesc> jobs)
 {
-    if (nLevel == kMap20)
-    {
-        RunCinemaScene(-1);
-        return;
+    if (nLevelNew == 5 && !(nCinemaSeen & 1)) {
+        nCinemaSeen |= 1;
+        DoBeforeCinemaScene(5, jobs);
     }
 
-    short nScene = nBeforeScene[nLevel];
+    menu_DrawTheMap(nLevel, nLevelNew, nLevelBest, jobs);
 
-    if (nScene)
-    {
-        if (!nCinemaSeen[nScene])
-        {
-            RunCinemaScene(nScene);
-            nCinemaSeen[nScene] = 1;
-        }
+    if (nLevelNew == 11 && !(nCinemaSeen & 2)) {
+        DoBeforeCinemaScene(11, jobs);
     }
 }
 
-int SyncScreenJob();
-
-int showmap(short nLevel, short nLevelNew, short nLevelBest)
-{
-    FadeOut(0);
-    EraseScreen(overscanindex);
-    GrabPalette();
-    BlackOut();
-
-    if (nLevelNew != 11) {
-        CheckBeforeScene(nLevelNew);
-    }
-
-	int selectedLevel;
-	menu_DrawTheMap(nLevel, nLevelNew, nLevelBest, [&](int lev){
-		gamestate = GS_LEVEL;
-		selectedLevel = lev;
-        if (lev != nLevelNew) STAT_Cancel();
-	});
-	SyncScreenJob();
-    if (selectedLevel == 11) {
-        CheckBeforeScene(selectedLevel);
-    }
-
-    return selectedLevel;
-}
-
-void DoAfterCinemaScene(int nLevel)
-{
-    short nAfterScene[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 7, 0, 0, 0, 0, 6 };
-
-    if (nAfterScene[nLevel]) {
-        RunCinemaScene(nAfterScene[nLevel]);
-    }
-}
-
-void DoFailedFinalScene()
-{
-    videoSetViewableArea(0, 0, xdim - 1, ydim - 1);
-
-    if (CDplaying()) {
-        fadecdaudio();
-    }
-
-    playCDtrack(9, false);
-    FadeToWhite();
-
-    RunCinemaScene(4);
-}
-
-void DoGameOverScene()
-{
-    FadeOut(0);
-    inputState.ClearAllInput();
-
-    NoClip();
-    overwritesprite(0, 0, kTile3591, 0, 2, kPalNormal, 16);
-    videoNextPage();
-    PlayGameOverSound();
-    //WaitAnyKey(3);
-    FadeOut(0);
-}
-
-
 
 static void GameDisplay(void)
 {
-    // End Section B
-
-    SetView1();
-
     if (levelnum == kMap20)
     {
-        LockEnergyTiles();
         DoEnergyTile();
         DrawClock();
     }
@@ -224,12 +126,6 @@ static void GameDisplay(void)
 		int nStringWidth = SmallFont->StringWidth(tex);
 		DrawText(twod, SmallFont, CR_UNTRANSLATED, 160 - nStringWidth / 2, 100, tex, DTA_FullscreenScale, FSMode_ScaleToFit43, DTA_VirtualWidth, 320, DTA_VirtualHeight, 200, TAG_DONE);
     }
-    if (M_Active())
-    {
-        D_ProcessEvents();
-    }
-
-    videoNextPage();
 }
 
 //---------------------------------------------------------------------------
@@ -246,6 +142,12 @@ void startmainmenu()
     StopAllSounds();
 }
 
+//---------------------------------------------------------------------------
+//
+// 
+//
+//---------------------------------------------------------------------------
+
 void drawmenubackground()
 {
     auto nLogoTile = EXHUMED ? kExhumedLogo : kPowerslaveLogo;
@@ -263,44 +165,90 @@ void drawmenubackground()
 
 }
 
+//---------------------------------------------------------------------------
+//
+// 
+//
+//---------------------------------------------------------------------------
 
 void CheckProgression()
 {
-    if (EndLevel)
+    TArray<JobDesc> jobs;
+    bool startlevel = false;
+    int mylevelnew = levelnew;
+
+    levelnew = -1;
+
+    if (GameAction >= 0)
     {
-        EndLevel = false;
-        FinishLevel();
-    }
-    if (levelnew > -1)
-    {
-        if (levelnew > 99)
+        if (GameAction < 1000)
         {
-            // end the game (but don't abort like the original game did!)
-            gamestate = GS_STARTUP;
-        }
-        else if (levelnew == -2)
-        {
-            // A savegame was loaded. Just start the level without any further actions.
-            gamestate = GS_LEVEL;
+            // start a new game on the given level
+            GameAction = -1;
+            mylevelnew = GameAction;
+            InitNewGame();
+            if (mylevelnew != 0) nBestLevel = mylevelnew - 1;
         }
         else
         {
-            // start a new game at the given level
-            if (!nNetPlayerCount && levelnew <= kMap20)
-            {
-                levelnew = showmap(levelnum, levelnew, nBestLevel);
-            }
-
-            if (levelnew > nBestLevel)
-            {
-                nBestLevel = levelnew;
-            }
-            InitNewGame();
+            // A savegame was loaded. Just start the level without any further actions.
+            GameAction = -1;
+            gamestate = GS_LEVEL;
+            return;
         }
     }
+    else if (EndLevel)
+    {
+        if (levelnum == 0) startmainmenu();
+        else FinishLevel(jobs);
+        EndLevel = false;
+    }
+    if (mylevelnew > -1 && mylevelnew < kMap20)
+    {
+        startlevel = true;
+        // start a new game at the given level
+        if (!nNetPlayerCount)
+        {
+            showmap(levelnum, mylevelnew, nBestLevel, jobs);
+        }
+        else
+            jobs.Push({ Create<DScreenJob>() }); // we need something in here even in the multiplayer case.
+    }
+    if (jobs.Size() > 0)
+    {
+        selectedlevelnew = mylevelnew;
+        RunScreenJob(jobs.Data(), jobs.Size(), [=](bool)
+            {
+                if (!startlevel) gamestate = GS_STARTUP;
+                else
+                {
+                    gamestate = GS_LEVEL;
 
+                    InitLevel(selectedlevelnew);
+                    tclocks = totalclock;
+#if 0
+                    // this would be the place to autosave upon level start
+                    if (!bInDemo && selectedlevelnew > nBestLevel && selectedlevelnew != 0 && selectedlevelnew <= kMap20) {
+                        menu_GameSave(SavePosition);
+                    }
+#endif
+                    if (selectedlevelnew > nBestLevel)
+                    {
+                        nBestLevel = selectedlevelnew;
+                    }
+
+                    if (selectedlevelnew == 11) nCinemaSeen |= 2;
+                    if (mylevelnew != selectedlevelnew) STAT_Cancel();
+                }
+            });
+    }
 }
 
+//---------------------------------------------------------------------------
+//
+// 
+//
+//---------------------------------------------------------------------------
 
 void GameLoop()
 {
@@ -317,7 +265,7 @@ void GameLoop()
 //
 //---------------------------------------------------------------------------
 
-int app_loop()// GameInterface::app_main()
+int GameInterface::app_main()
 {
     InitGame();
     gamestate = GS_STARTUP;
@@ -336,6 +284,9 @@ int app_loop()// GameInterface::app_main()
             case GS_STARTUP:
                 totalclock = 0;
                 ototalclock = 0;
+                levelnew = -1;
+                GameAction = -1;
+                EndLevel = false;
 
                 if (userConfig.CommandMap.IsNotEmpty())
                 {
@@ -367,10 +318,13 @@ int app_loop()// GameInterface::app_main()
 
             }
             videoNextPage();
-            videoSetBrightness(0);	// immediately reset this so that the value doesn't stick around in the backend.
         }
         catch (CRecoverableError& err)
         {
+            // Clear all progression sensitive variables here.
+            levelnew = -1;
+            GameAction = -1;
+            EndLevel = false;
             C_FullConsole();
             Printf(TEXTCOLOR_RED "%s\n", err.what());
         }
@@ -379,84 +333,6 @@ int app_loop()// GameInterface::app_main()
 
 
 
-int GameInterface::app_main()
-{
-    int nMenu = 0;
-
-    InitGame();
-    if (!userConfig.nologo)
-    {
-        DoTitle([](bool) { gamestate = GS_MENUSCREEN; });
-        SyncScreenJob();
-        gamestate = GS_LEVEL;
-    }
-    // loc_11811:
-    if (forcelevel > -1)
-    {
-        levelnew = forcelevel;
-        goto STARTGAME1;
-    }
-
-    SavePosition = -1;
-    nMenu = menu_Menu(0);
-    switch (nMenu)
-    {
-    case 3:
-        forcelevel = 0;
-        goto STARTGAME2;
-    case 6:
-        goto GAMELOOP;
-    }
-STARTGAME1:
-    levelnew = 1;
-    levelnum = 1;
-    if (!nNetPlayerCount) {
-        FadeOut(0);
-    }
-STARTGAME2:
-
-    InitNewGame();
-
-    nBestLevel = levelnew - 1;
-LOOP1:
-
-    if (!bInDemo && levelnew > nBestLevel && levelnew != 0 && levelnew <= kMap20 && SavePosition > -1) {
-        menu_GameSave(SavePosition);
-    }
-    if (!nNetPlayerCount && levelnew > 0 && levelnew <= kMap20) {
-        levelnew = showmap(levelnum, levelnew, nBestLevel);
-    }
-
-    if (levelnew > nBestLevel) {
-        nBestLevel = levelnew;
-    }
-    InitLevel(levelnew);
-    tclocks = totalclock;
-    levelnew = -1;
-    // Game Loop
-GAMELOOP:
-    while (1)
-    {
-        if (levelnew >= 0)
-        {
-            goto LOOP1;
-        }
-
-        HandleAsync();
-        C_RunDelayedCommands();
-
-        updatePauseStatus();
-        GameLoop();
-        GameDisplay();
-
-        if (EndLevel)
-		{
-            EndLevel = false;
-            FinishLevel();
-		}
-    }
-}
-
 
 
 END_PS_NS
diff --git a/source/exhumed/src/init.cpp b/source/exhumed/src/init.cpp
index 1d8f0a313..91ae9f476 100644
--- a/source/exhumed/src/init.cpp
+++ b/source/exhumed/src/init.cpp
@@ -179,6 +179,7 @@ uint8_t LoadLevel(int nMap)
 
 void InitLevel(int level)
 {
+    levelnum = level;
     StopCD();
     if (!LoadLevel(level)) {
         I_Error("Can't load level %d...\n", level);
@@ -218,7 +219,7 @@ void InitLevel(int level)
 void InitNewGame()
 {
     bCamera = false;
-    ClearCinemaSeen();
+    nCinemaSeen = 0;
     PlayerCount = 0;
 
     for (int i = 0; i < nTotalPlayers; i++)
diff --git a/source/exhumed/src/light.cpp b/source/exhumed/src/light.cpp
index f6923d640..11e85b7a4 100644
--- a/source/exhumed/src/light.cpp
+++ b/source/exhumed/src/light.cpp
@@ -79,13 +79,11 @@ int LoadPaletteLookups()
         
         bGreenPal = 0;
 
-#ifdef USE_OPENGL
         // These 3 tables do not have normal gradients. The others work without adjustment.
         // Other changes than altering the fog gradient are not necessary.
         lookups.tables[kPalTorch].ShadeFactor = lookups.tables[kPalTorch2].ShadeFactor = (numshades - 2) / 20.f;
         lookups.tables[kPalNoTorch].ShadeFactor = lookups.tables[kPalNoTorch2].ShadeFactor = (numshades - 2) / 4.f;
         lookups.tables[kPalBrite].ShadeFactor = lookups.tables[kPalBrite].ShadeFactor = (numshades - 2) / 128.f;
-#endif
 
     }
 
@@ -146,48 +144,6 @@ void GrabPalette()
     videoTintBlood(0, 0, 0);
 }
 
-void BlackOut()
-{
-    videoTintBlood(0, 0, 0);
-}
-
-void RestorePalette()
-{
-    videoTintBlood(0, 0, 0);
-}
-
-void FadeToWhite()
-{
-    // fixme
-    videoTintBlood(255, 255, 255);
-    videoNextPage();
-}
-
-void FadeOut(int bFadeMusic)
-{
-    if (bFadeMusic) StopCD();
-    videoTintBlood(-255, -255, -255);
-    videoNextPage();
-
-    EraseScreen(overscanindex);
-}
-
-void StartFadeIn()
-{
-    //fadecurpal = curpal;
-}
-
-int DoFadeIn()
-{
-    videoNextPage();
-    return 0;
-}
-
-void FadeIn()
-{
-    videoNextPage();
-}
-
 void FixPalette()
 {
     if (!nPalDiff) {
diff --git a/source/exhumed/src/menu.cpp b/source/exhumed/src/menu.cpp
index bb3e12fda..6c95f586e 100644
--- a/source/exhumed/src/menu.cpp
+++ b/source/exhumed/src/menu.cpp
@@ -50,12 +50,10 @@ BEGIN_PS_NS
 
 GameStat GameStats;
 
-short nCinemaSeen[30];
+uint8_t nCinemaSeen;
 
 uint8_t energytile[66 * 66] = {0};
 
-short SavePosition = -1;
-
 uint8_t *cur;
 uint8_t *dest;
 
@@ -67,11 +65,6 @@ short word_9AB5B = 0;
 int keytimer = 0;
 
 
-void ClearCinemaSeen()
-{
-    memset(nCinemaSeen, 0, sizeof(nCinemaSeen));
-}
-
 unsigned int menu_RandomBit2()
 {
     unsigned int result = nRandom & 1;
@@ -300,7 +293,7 @@ void menu_GameSave2(FILE* fp)
 {
     memset(&GameStats, 0, sizeof(GameStats));
 
-    GameStats.nMap = (uint8_t)levelnew;
+    GameStats.nMap = (uint8_t)levelnum;
     GameStats.nWeapons = nPlayerWeapons[nLocalPlayer];
     GameStats.nCurrentWeapon = PlayerList[nLocalPlayer].nCurrentWeapon;
     GameStats.clip = nPlayerClip[nLocalPlayer];
diff --git a/source/exhumed/src/menu.h b/source/exhumed/src/menu.h
index 4d1827d7d..23e2706fd 100644
--- a/source/exhumed/src/menu.h
+++ b/source/exhumed/src/menu.h
@@ -44,11 +44,8 @@ extern GameStat GameStats;
 
 extern unsigned char cinemapal[];
 
-extern short SavePosition;
-
 int showmap(short nLevel, short nLevelNew, short nLevelBest);
 
-void ClearCinemaSeen();
 void menu_DoPlasma();
 int menu_Menu(int val);
 short menu_GameLoad(int nSlot);
@@ -56,14 +53,10 @@ void menu_GameLoad2(FILE *fp, bool bIsDemo = false);
 void menu_GameSave2(FILE *fp);
 void menu_GameSave(int nSaveSlot);
 
-void menu_DrawTheMap(int nLevel, int nLevelNew, int nLevelBest, std::function<void(int)> completion);
+void menu_DrawTheMap(int nLevel, int nLevelNew, int nLevelBest, TArray<JobDesc> &jobs);
 
 void DoEnergyTile();
 
-void DoFailedFinalScene();
-
-void DoAfterCinemaScene(int nLevel);
-
 void InitEnergyTile();
 
 END_PS_NS
diff --git a/source/exhumed/src/object.cpp b/source/exhumed/src/object.cpp
index ed376da95..0dd8350c3 100644
--- a/source/exhumed/src/object.cpp
+++ b/source/exhumed/src/object.cpp
@@ -2554,7 +2554,7 @@ void PostProcess()
         }
     }
 
-    if (levelnew != kMap20)
+    if (levelnum != kMap20)
     {
         // esi is i
         for (i = 0; i < numsectors; i++)
diff --git a/source/exhumed/src/osdcmds.cpp b/source/exhumed/src/osdcmds.cpp
index d0f87ace4..f1f12e7ac 100644
--- a/source/exhumed/src/osdcmds.cpp
+++ b/source/exhumed/src/osdcmds.cpp
@@ -83,8 +83,7 @@ static int osdcmd_map(CCmdFuncPtr parm)
     {
         if (mapList[i].labelName.CompareNoCase(mapname) == 0)
         {
-			levelnew = i;
-			levelnum = i;
+			GameAction = i;
 			return CCMD_OK;
         }
     }
@@ -117,8 +116,7 @@ static int osdcmd_changelevel(CCmdFuncPtr parm)
         return CCMD_SHOWHELP;
     }
 
-    levelnew = nLevel;
-    levelnum = nLevel;
+    GameAction = nLevel;
 
     return CCMD_OK;
 }
diff --git a/source/exhumed/src/player.cpp b/source/exhumed/src/player.cpp
index b6345157d..9e5b84e75 100644
--- a/source/exhumed/src/player.cpp
+++ b/source/exhumed/src/player.cpp
@@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #include "sound.h"
 #include "buildtiles.h"
 #include "gstrings.h"
+#include "gamestate.h"
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
@@ -2960,18 +2961,8 @@ loc_1BD2E:
                         }
                         else
                         {
-                            if (CDplaying()) {
-                                fadecdaudio();
-                            }
-
-                            if (levelnum == 20) {
-                                DoFailedFinalScene();
-                            }
-                            else {
-                                DoGameOverScene();
-                            }
-
-                            levelnew = 100;
+                            DoGameOverScene((levelnum == 20));
+                            return;
                         }
                     }
                 }
diff --git a/source/exhumed/src/ramses.cpp b/source/exhumed/src/ramses.cpp
index a26fa368e..380a891d9 100644
--- a/source/exhumed/src/ramses.cpp
+++ b/source/exhumed/src/ramses.cpp
@@ -489,8 +489,7 @@ int DoSpiritHead()
             {
                 if (!CDplaying())
                 {
-                    levelnew = levelnum + 1;
-                    fadecdaudio();
+                    EndLevel = 2;
                 }
             }
         }
diff --git a/source/exhumed/src/save.cpp b/source/exhumed/src/save.cpp
index 0f1e86b45..fb0bbe156 100644
--- a/source/exhumed/src/save.cpp
+++ b/source/exhumed/src/save.cpp
@@ -28,7 +28,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 BEGIN_PS_NS
 
-extern int MenuExitCondition;
 void SaveTextureState();
 void LoadTextureState();
 
@@ -61,7 +60,7 @@ bool GameInterface::LoadGame(FSaveGameNode* sv)
     parallaxtype = 2;
     g_visibility = 2048;
     ototalclock = totalclock;
-    MenuExitCondition = 6;
+    GameAction = 1000;
 
     if (levelnum > 15)
     {
diff --git a/source/exhumed/src/view.cpp b/source/exhumed/src/view.cpp
index dae89d13d..12ea1601b 100644
--- a/source/exhumed/src/view.cpp
+++ b/source/exhumed/src/view.cpp
@@ -230,11 +230,6 @@ void ResetView()
 #endif
 }
 
-void SetView1()
-{
-}
-
-
 static inline int interpolate16(int a, int b, int smooth)
 {
     return a + mulscale16(b - a, smooth);
@@ -449,7 +444,7 @@ void DrawView(int smoothRatio, bool sceneonly)
                     if ((bSubTitles && !subtitleOverlay.AdvanceCinemaText(totalclock)) || inputState.CheckAllInput())
                     {
 						inputState.ClearAllInput();
-                        levelnew = levelnum + 1;
+                        EndLevel = 2;
 
                         if (CDplaying()) {
                             fadecdaudio();
diff --git a/source/exhumed/src/view.h b/source/exhumed/src/view.h
index f7fd1a5c6..93ba55ecf 100644
--- a/source/exhumed/src/view.h
+++ b/source/exhumed/src/view.h
@@ -28,7 +28,6 @@ extern short besttarget;
 extern short bCamera;
 
 void InitView();
-void SetView1();
 void DrawStatusBar();
 void DrawView(int smoothRatio, bool sceneonly = false);
 void ResetView();
diff --git a/wadsrc/static/engine/menudef.txt b/wadsrc/static/engine/menudef.txt
index 0ddf06302..ede3768f9 100644
--- a/wadsrc/static/engine/menudef.txt
+++ b/wadsrc/static/engine/menudef.txt
@@ -61,7 +61,7 @@ LISTMENU "MainMenu"
 		linespacing 22
 		NativeTextItem "3460", "n", "StartGame", 1
 		NativeTextItem "3461", "l", "LoadGameMenu"
-		NativeTextItem "3462", "m", "StartGame", 3
+		NativeTextItem "3462", "m", "StartGame", 0
 		NativeTextItem "3463", "v", "OptionsMenu"
 		NativeTextItem "3464", "q", "QuitMenu"
 	}
@@ -150,7 +150,7 @@ LISTMENU "IngameMenu"
 		linespacing 22
 		NativeTextItem "3460", "n", "StartGame", 1
 		NativeTextItem "3461", "l", "LoadGameMenu"
-		NativeTextItem "3462", "m", "StartGame", 3
+		NativeTextItem "3462", "m", "StartGame", 0
 		NativeTextItem "3463", "v", "OptionsMenu"
 		NativeTextItem "3464", "q", "QuitMenu"
 	}