From 4ad327d7e09b89888fe5587c9002ae9743a8f1af Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Tue, 29 Jan 2019 23:45:14 +0100
Subject: [PATCH] - moved G_ChangeLevel and other exit functions into
 FLevelLocals.

---
 src/d_main.cpp               |  2 +-
 src/d_net.cpp                |  4 +--
 src/dobjgc.cpp               |  2 +-
 src/fragglescript/t_cmd.cpp  |  6 ++--
 src/fragglescript/t_func.cpp |  4 +--
 src/g_level.cpp              | 61 ++++++++++++++++++------------------
 src/g_level.h                |  7 -----
 src/g_levellocals.h          |  5 +++
 src/p_acs.cpp                |  2 +-
 src/p_enemy.cpp              |  2 +-
 src/p_interaction.cpp        |  2 +-
 src/p_lnspec.cpp             | 12 +++----
 src/p_spec.cpp               |  4 +--
 13 files changed, 56 insertions(+), 57 deletions(-)

diff --git a/src/d_main.cpp b/src/d_main.cpp
index cefd446b92..55db3cc713 100644
--- a/src/d_main.cpp
+++ b/src/d_main.cpp
@@ -170,7 +170,7 @@ CUSTOM_CVAR (Int, fraglimit, 0, CVAR_SERVERINFO)
 			if (playeringame[i] && self <= D_GetFragCount(&players[i]))
 			{
 				Printf ("%s\n", GStrings("TXT_FRAGLIMIT"));
-				G_ExitLevel (0, false);
+				level.ExitLevel (0, false);
 				break;
 			}
 		}
diff --git a/src/d_net.cpp b/src/d_net.cpp
index abd703d133..33a6a3f3c5 100644
--- a/src/d_net.cpp
+++ b/src/d_net.cpp
@@ -2222,7 +2222,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
 		// Using LEVEL_NOINTERMISSION tends to throw the game out of sync.
 		// That was a long time ago. Maybe it works now?
 		level.flags |= LEVEL_CHANGEMAPCHEAT;
-		G_ChangeLevel(s, pos, 0);
+		level.ChangeLevel(s, pos, 0);
 		break;
 
 	case DEM_SUICIDE:
@@ -2659,7 +2659,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
 
 	case DEM_FINISHGAME:
 		// Simulate an end-of-game action
-		G_ChangeLevel(NULL, 0, 0);
+		level.ChangeLevel(NULL, 0, 0);
 		break;
 
 	case DEM_NETEVENT:
diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp
index 94d6a946c7..2b8aefd587 100644
--- a/src/dobjgc.cpp
+++ b/src/dobjgc.cpp
@@ -296,7 +296,7 @@ static void MarkRoot()
 	}
 	// Mark sectors.
 	
-	for auto Level : AllLevels())
+	for (auto Level : AllLevels())
 	{
 		Level->Mark();
 	}
diff --git a/src/fragglescript/t_cmd.cpp b/src/fragglescript/t_cmd.cpp
index f3673c2776..593b72e036 100644
--- a/src/fragglescript/t_cmd.cpp
+++ b/src/fragglescript/t_cmd.cpp
@@ -77,7 +77,7 @@ static void FS_Gimme(const char * what)
 //
 //==========================================================================
 
-void FS_MapCmd(FScanner &sc)
+void FS_MapCmd(FLevelLocals *Level, FScanner &sc)
 {
 	char nextmap[9];
 	int NextSkill = -1;
@@ -108,7 +108,7 @@ void FS_MapCmd(FScanner &sc)
 			flags &= ~(CHANGELEVEL_RESETINVENTORY|CHANGELEVEL_RESETHEALTH);
 		}
 	}
-	G_ChangeLevel(nextmap, 0, flags, NextSkill);
+	Level->ChangeLevel(nextmap, 0, flags, NextSkill);
 }
 
 //==========================================================================
@@ -168,7 +168,7 @@ void FS_EmulateCmd(FLevelLocals *Level, char * string)
 		}
 		else if (sc.Compare("map"))
 		{
-			FS_MapCmd(sc);
+			FS_MapCmd(Level, sc);
 		}
 		else if (sc.Compare("gr_fogdensity"))
 		{
diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp
index e6f2a583ef..1dccf3f35c 100644
--- a/src/fragglescript/t_func.cpp
+++ b/src/fragglescript/t_func.cpp
@@ -608,7 +608,7 @@ void FParser::SF_Clock(void)
 
 void FParser::SF_ExitLevel(void)
 {
-	G_ExitLevel(0, false);
+	Level->ExitLevel(0, false);
 }
 
 //==========================================================================
@@ -2825,7 +2825,7 @@ void FParser::SF_AmbientSound(void)
 
 void FParser::SF_ExitSecret(void)
 {
-	G_SecretExitLevel(0);
+	Level->SecretExitLevel(0);
 }
 
 
diff --git a/src/g_level.cpp b/src/g_level.cpp
index 24fa264a52..94a9850666 100644
--- a/src/g_level.cpp
+++ b/src/g_level.cpp
@@ -569,16 +569,19 @@ static bool		unloading;
 
 EXTERN_CVAR(Bool, sv_singleplayerrespawn)
 
-void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill)
+void FLevelLocals::ChangeLevel(const char *levelname, int position, int flags, int nextSkill)
 {
-	level_info_t *nextinfo = NULL;
+	if (this != currentUILevel) return;	// only the primary level may exit.
+
+	FString nextlevel;
+	level_info_t *nextinfo = nullptr;
 
 	if (unloading)
 	{
 		Printf (TEXTCOLOR_RED "Unloading scripts cannot exit the level again.\n");
 		return;
 	}
-	if (gameaction == ga_completed && !(level.i_compatflags2 & COMPATF2_MULTIEXIT))	// do not exit multiple times.
+	if (gameaction == ga_completed && !(i_compatflags2 & COMPATF2_MULTIEXIT))	// do not exit multiple times.
 	{
 		return;
 	}
@@ -587,9 +590,9 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
 	{
 		// end the game
 		levelname = NULL;
-		if (!level.NextMap.Compare("enDSeQ",6))
+		if (!NextMap.Compare("enDSeQ",6))
 		{
-			nextlevel = level.NextMap;	// If there is already an end sequence please leave it alone!
+			nextlevel = NextMap;	// If there is already an end sequence please leave it alone!
 		}
 		else 
 		{
@@ -625,15 +628,14 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
 
 	if (flags & CHANGELEVEL_NOINTERMISSION)
 	{
-		level.flags |= LEVEL_NOINTERMISSION;
+		flags |= LEVEL_NOINTERMISSION;
 	}
 
-	cluster_info_t *thiscluster = FindClusterInfo (level.cluster);
+	cluster_info_t *thiscluster = FindClusterInfo (cluster);
 	cluster_info_t *nextcluster = nextinfo? FindClusterInfo (nextinfo->cluster) : NULL;
 
 	startpos = position;
-	gameaction = ga_completed;
-	level.SetMusicVolume(1.0);
+	SetMusicVolume(1.0);
 		
 	if (nextinfo != NULL) 
 	{
@@ -655,18 +657,18 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
 
 	// [RH] Give scripts a chance to do something
 	unloading = true;
-	level.Behaviors.StartTypedScripts (SCRIPT_Unloading, NULL, false, 0, true);
+	Behaviors.StartTypedScripts (SCRIPT_Unloading, NULL, false, 0, true);
 	// [ZZ] safe world unload
 	E_WorldUnloaded();
 	// [ZZ] unsafe world unload (changemap != map)
 	E_WorldUnloadedUnsafe();
 	unloading = false;
 
-	STAT_ChangeLevel(nextlevel, &level);
+	STAT_ChangeLevel(nextlevel, this);
 
 	if (thiscluster && (thiscluster->flags & CLUSTER_HUB))
 	{
-		if ((level.flags & LEVEL_NOINTERMISSION) || ((nextcluster == thiscluster) && !(thiscluster->flags & CLUSTER_ALLOWINTERMISSION)))
+		if ((flags & LEVEL_NOINTERMISSION) || ((nextcluster == thiscluster) && !(thiscluster->flags & CLUSTER_ALLOWINTERMISSION)))
 			NoWipe = 35;
 		D_DrawIcon = "TELEICON";
 	}
@@ -682,7 +684,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
 
 			// If this is co-op, respawn any dead players now so they can
 			// keep their inventory on the next map.
-			if ((multiplayer || level.flags2 & LEVEL2_ALLOWRESPAWN || sv_singleplayerrespawn || !!G_SkillProperty(SKILLP_PlayerRespawn))
+			if ((multiplayer || flags2 & LEVEL2_ALLOWRESPAWN || sv_singleplayerrespawn || !!G_SkillProperty(SKILLP_PlayerRespawn))
 				&& !deathmatch && player->playerstate == PST_DEAD)
 			{
 				// Copied from the end of P_DeathThink [[
@@ -693,10 +695,13 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
 					player->mo->special1 = 0;
 				}
 				// ]]
-				level.DoReborn(i, false);
+				DoReborn(i, false);
 			}
 		}
 	}
+	// Set global transition state.
+	gameaction = ga_completed;
+	::nextlevel = nextlevel;
 }
 
 //==========================================================================
@@ -704,20 +709,15 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
 //
 //==========================================================================
 
-const char *G_GetExitMap()
+const char *FLevelLocals::GetSecretExitMap()
 {
-	return level.NextMap;
-}
+	const char *nextmap = NextMap;
 
-const char *G_GetSecretExitMap()
-{
-	const char *nextmap = level.NextMap;
-
-	if (level.NextSecretMap.Len() > 0)
+	if (NextSecretMap.Len() > 0)
 	{
-		if (P_CheckMapData(level.NextSecretMap))
+		if (P_CheckMapData(NextSecretMap))
 		{
-			nextmap = level.NextSecretMap;
+			nextmap = NextSecretMap;
 		}
 	}
 	return nextmap;
@@ -728,16 +728,17 @@ const char *G_GetSecretExitMap()
 //
 //==========================================================================
 
-void G_ExitLevel (int position, bool keepFacing)
+
+void FLevelLocals::ExitLevel (int position, bool keepFacing)
 {
-	level.flags3 |= LEVEL3_EXITNORMALUSED;
-	G_ChangeLevel(G_GetExitMap(), position, keepFacing ? CHANGELEVEL_KEEPFACING : 0);
+	flags3 |= LEVEL3_EXITNORMALUSED;
+	ChangeLevel(NextMap, position, keepFacing ? CHANGELEVEL_KEEPFACING : 0);
 }
 
-void G_SecretExitLevel (int position) 
+void FLevelLocals::SecretExitLevel (int position)
 {
-	level.flags3 |= LEVEL3_EXITSECRETUSED;
-	G_ChangeLevel(G_GetSecretExitMap(), position, 0);
+	flags3 |= LEVEL3_EXITSECRETUSED;
+	ChangeLevel(GetSecretExitMap(), position, 0);
 }
 
 //==========================================================================
diff --git a/src/g_level.h b/src/g_level.h
index bdba32b7be..8b83ed0439 100644
--- a/src/g_level.h
+++ b/src/g_level.h
@@ -454,11 +454,6 @@ void G_DeferedInitNew (const char *mapname, int skill = -1);
 struct FGameStartup;
 void G_DeferedInitNew (FGameStartup *gs);
 
-void G_ExitLevel (int position, bool keepFacing);
-void G_SecretExitLevel (int position);
-const char *G_GetExitMap();
-const char *G_GetSecretExitMap();
-
 enum 
 {
 	CHANGELEVEL_KEEPFACING = 1,
@@ -470,8 +465,6 @@ enum
 	CHANGELEVEL_PRERAISEWEAPON = 64,
 };
 
-void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill=-1);
-
 void G_DoLoadLevel (const FString &MapName, int position, bool autosave, bool newGame);
 
 cluster_info_t *FindClusterInfo (int cluster);
diff --git a/src/g_levellocals.h b/src/g_levellocals.h
index 17c834788b..a8d1486dcd 100644
--- a/src/g_levellocals.h
+++ b/src/g_levellocals.h
@@ -92,6 +92,7 @@ class DSeqNode;
 struct FStrifeDialogueNode;
 class DAutomapBase;
 struct wbstartstruct_t;
+class DSectorMarker;
 
 typedef TMap<int, int> FDialogueIDMap;				// maps dialogue IDs to dialogue array index (for ACS)
 typedef TMap<FName, int> FDialogueMap;				// maps actor class names to dialogue array index
@@ -225,6 +226,10 @@ public:
 	bool DoCompleted(FString nextlevel, wbstartstruct_t &wminfo);
 	void StartTravel();
 	int FinishTravel();
+	void ChangeLevel(const char *levelname, int position, int flags, int nextSkill = -1);
+	const char *GetSecretExitMap();
+	void ExitLevel(int position, bool keepFacing);
+	void SecretExitLevel(int position);
 	void DoLoadLevel(const FString &nextmapname, int position, bool autosave, bool newGame);
 
 
diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index 18846570a3..a51343c7f8 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -9896,7 +9896,7 @@ scriptwait:
 
 		case PCD_CHANGELEVEL:
 			{
-				G_ChangeLevel(Level->Behaviors.LookupString(STACK(4)), STACK(3), STACK(2), STACK(1));
+				Level->ChangeLevel(Level->Behaviors.LookupString(STACK(4)), STACK(3), STACK(2), STACK(1));
 				sp -= 4;
 			}
 			break;
diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp
index 162e9a76cd..f976285108 100644
--- a/src/p_enemy.cpp
+++ b/src/p_enemy.cpp
@@ -3175,7 +3175,7 @@ void A_BossDeath(AActor *self)
 	if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT))
 		return;
 
-	G_ExitLevel (0, false);
+	Level->ExitLevel (0, false);
 }
 
 //----------------------------------------------------------------------------
diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp
index dfaeebea88..448892cf3f 100644
--- a/src/p_interaction.cpp
+++ b/src/p_interaction.cpp
@@ -543,7 +543,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
 				fraglimit <= D_GetFragCount (source->player))
 			{
 				Printf ("%s\n", GStrings("TXT_FRAGLIMIT"));
-				G_ExitLevel (0, false);
+				Level->ExitLevel (0, false);
 			}
 		}
 	}
diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp
index 04d7d9337c..fbb2dc8735 100644
--- a/src/p_lnspec.cpp
+++ b/src/p_lnspec.cpp
@@ -1060,9 +1060,9 @@ FUNC(LS_Generic_Lift)
 FUNC(LS_Exit_Normal)
 // Exit_Normal (position)
 {
-	if (Level->CheckIfExitIsGood (it, FindLevelInfo(G_GetExitMap())))
+	if (Level->CheckIfExitIsGood (it, FindLevelInfo(Level->NextMap)))
 	{
-		G_ExitLevel (arg0, false);
+		Level->ExitLevel (arg0, false);
 		return true;
 	}
 	return false;
@@ -1071,9 +1071,9 @@ FUNC(LS_Exit_Normal)
 FUNC(LS_Exit_Secret)
 // Exit_Secret (position)
 {
-	if (Level->CheckIfExitIsGood (it, FindLevelInfo(G_GetSecretExitMap())))
+	if (Level->CheckIfExitIsGood (it, FindLevelInfo(Level->GetSecretExitMap())))
 	{
-		G_SecretExitLevel (arg0);
+		Level->SecretExitLevel (arg0);
 		return true;
 	}
 	return false;
@@ -1088,7 +1088,7 @@ FUNC(LS_Teleport_NewMap)
 
 		if (info && Level->CheckIfExitIsGood (it, info))
 		{
-			G_ChangeLevel(info->MapName, arg1, arg2 ? CHANGELEVEL_KEEPFACING : 0);
+			Level->ChangeLevel(info->MapName, arg1, arg2 ? CHANGELEVEL_KEEPFACING : 0);
 			return true;
 		}
 	}
@@ -1183,7 +1183,7 @@ FUNC(LS_Teleport_EndGame)
 {
 	if (!backSide && Level->CheckIfExitIsGood (it, NULL))
 	{
-		G_ChangeLevel(NULL, 0, 0);
+		Level->ChangeLevel(NULL, 0, 0);
 		return true;
 	}
 	return false;
diff --git a/src/p_spec.cpp b/src/p_spec.cpp
index effc55eed6..7271e94014 100644
--- a/src/p_spec.cpp
+++ b/src/p_spec.cpp
@@ -463,7 +463,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
 				if (!(player->cheats & (CF_GODMODE|CF_GODMODE2))) P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype);
 				if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
 				{
-					G_ExitLevel(0, false);
+					Level->ExitLevel(0, false);
 				}
 				if (sector->Flags & SECF_DMGTERRAINFX)
 				{
@@ -678,7 +678,7 @@ void P_UpdateSpecials (FLevelLocals *Level)
 		if (Level->maptime >= (int)(timelimit * TICRATE * 60))
 		{
 			Printf ("%s\n", GStrings("TXT_TIMELIMIT"));
-			G_ExitLevel(0, false);
+			Level->ExitLevel(0, false);
 		}
 	}
 }