diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index a79f1e711fe7d9f297d5d71f656d6c1abbc61449..11e067f244d457035a8d4331b48620ab9c375dd0 100755
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -5304,7 +5304,7 @@ boolean TryRunTics(tic_t realtics)
 	{
 		COM_BufTicker();
 		if (mapchangepending)
-			D_MapChange(-1, 0, false, ultimatemode, false, 2, false, fromlevelselect); // finish the map change
+			D_MapChange(-1, 0, ultimatemode, false, 2, false, fromlevelselect); // finish the map change
 	}
 
 	NetUpdate();
diff --git a/src/d_main.c b/src/d_main.c
index 9d7ae437915133f9d6b871f50c11741a91725fb2..0825fc9745266bb6e9b1edba5e324609ce259d63 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -1721,7 +1721,7 @@ void D_SRB2Main(void)
 				I_Error("You need to unlock this level before you can warp to it!\n");
 			else
 			{
-				D_MapChange(pstartmap, gametype, false, ultimatemode, true, 0, false, false);
+				D_MapChange(pstartmap, gametype, ultimatemode, true, 0, false, false);
 			}
 		}
 	}
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index c7599d6bbc83c41e0ff2d415620870955cb71242..1905afa0f2b8ff660c34ec0f4a11b85598a7aae4 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -64,6 +64,7 @@
 static void Got_NameAndColor(UINT8 **cp, INT32 playernum);
 static void Got_WeaponPref(UINT8 **cp, INT32 playernum);
 static void Got_Mapcmd(UINT8 **cp, INT32 playernum);
+static void Got_Newworld(UINT8 **cp, INT32 playernum);
 static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum);
 static void Got_Switchworld(UINT8 **cp, INT32 playernum);
 static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum);
@@ -454,6 +455,7 @@ void D_RegisterServerCommands(void)
 	RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor);
 	RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref);
 	RegisterNetXCmd(XD_MAP, Got_Mapcmd);
+	RegisterNetXCmd(XD_NEWWORLD, Got_Newworld);
 	RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd);
 	RegisterNetXCmd(XD_SWITCHWORLD, Got_Switchworld);
 	RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd);
@@ -1748,7 +1750,6 @@ boolean mapchangepending = false;
   *
   * \param mapnum          Map number to change to.
   * \param gametype        Gametype to switch to.
-  * \param addworld        Loads a separate world.
   * \param pultmode        Is this 'Ultimate Mode'?
   * \param resetplayers    1 to reset player scores and lives and such, 0 not to.
   * \param delay           Determines how the function will be executed: 0 to do
@@ -1758,7 +1759,7 @@ boolean mapchangepending = false;
   * \sa D_GameTypeChanged, Command_Map_f
   * \author Graue <graue@oceanbase.org>
   */
-void D_MapChange(INT32 mapnum, INT32 newgametype, boolean addworld, boolean pultmode, boolean resetplayers, INT32 delay, boolean skipprecutscene, boolean FLS)
+void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean resetplayers, INT32 delay, boolean skipprecutscene, boolean FLS)
 {
 	static char buf[2+MAX_WADPATH+1+4];
 	static char *buf_p = buf;
@@ -1809,8 +1810,6 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean addworld, boolean pult
 			flags |= 1<<2;
 		if (FLS)
 			flags |= 1<<3;
-		if (addworld)
-			flags |= 1<<4;
 		WRITEUINT8(buf_p, flags);
 
 		// new gametype value
@@ -1827,7 +1826,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean addworld, boolean pult
 
 		// spawn the server if needed
 		// reset players if there is a new one
-		if (!IsPlayerAdmin(consoleplayer) && !addworld)
+		if (!IsPlayerAdmin(consoleplayer))
 		{
 			if (SV_SpawnServer())
 				buf[0] &= ~(1<<1);
@@ -1842,6 +1841,22 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean addworld, boolean pult
 	}
 }
 
+// Sends a command to add a new world.
+// It's as simple as that.
+void D_AddWorld(INT32 mapnum)
+{
+	char buf[MAX_WADPATH+1];
+	char *buf_p = buf;
+
+	CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d\n", mapnum);
+
+	I_Assert(W_CheckNumForName(mapname) != LUMPERROR);
+
+	WRITESTRINGN(buf_p, G_BuildMapName(mapnum), MAX_WADPATH);
+
+	SendNetXCmd(XD_NEWWORLD, buf, buf_p - buf);
+}
+
 static char *
 ConcatCommandArgv (int start, int end)
 {
@@ -2069,7 +2084,10 @@ static void Command_Map_f(void)
 	}
 	tutorialmode = false; // warping takes us out of tutorial mode
 
-	D_MapChange(newmapnum, newgametype, addworld, false, newresetplayers, 0, false, fromlevelselect);
+	if (addworld)
+		D_AddWorld(newmapnum);
+	else
+		D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, fromlevelselect);
 
 	Z_Free(realmapname);
 }
@@ -2083,8 +2101,6 @@ static void Command_Map_f(void)
   */
 static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
 {
-	player_t *player;
-	boolean addworld;
 	char mapname[MAX_WADPATH+1];
 	UINT8 flags;
 	INT32 resetplayer = 1, lastgametype;
@@ -2093,9 +2109,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
 
 	flags = READUINT8(*cp);
 
-	addworld = ((flags & (1<<4)) != 0);
-
-	if (!addworld && playernum != serverplayer && !IsPlayerAdmin(playernum))
+	if (playernum != serverplayer && !IsPlayerAdmin(playernum))
 	{
 		CONS_Alert(CONS_WARNING, M_GetText("Illegal map change received from %s\n"), player_names[playernum]);
 		if (server)
@@ -2103,8 +2117,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
 		return;
 	}
 
-	player = &players[playernum];
-
 	if (chmappending)
 		chmappending--;
 
@@ -2136,8 +2148,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
 	{
 		DEBFILE(va("Warping to %s [resetplayer=%d lastgametype=%d gametype=%d cpnd=%d]\n",
 			mapname, resetplayer, lastgametype, gametype, chmappending));
-		if (!addworld)
-			CONS_Printf(M_GetText("Speeding off to level...\n"));
+		CONS_Printf(M_GetText("Speeding off to level...\n"));
 	}
 
 	if (demoplayback && !timingdemo)
@@ -2159,7 +2170,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
 	mapnumber = M_MapNumber(mapname[3], mapname[4]);
 	LUA_HookInt(mapnumber, HOOK(MapChange));
 
-	G_InitNew(player, mapname, addworld, ultimatemode, resetplayer, skipprecutscene, FLS);
+	G_InitNew(mapname, ultimatemode, resetplayer, skipprecutscene, FLS);
 	if (demoplayback && !timingdemo)
 		precache = true;
 	if (timingdemo)
@@ -2172,6 +2183,24 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
 	demo_start = true;
 }
 
+/** Receives a new world command and creates a new one.
+  *
+  * \param cp        Data buffer.
+  * \param playernum Player number responsible for the message.
+  * \sa D_MapChange
+  */
+static void Got_Newworld(UINT8 **cp, INT32 playernum)
+{
+	(void)playernum;
+
+	char mapname[MAX_WADPATH+1];
+	READSTRINGN(*cp, mapname, MAX_WADPATH);
+
+	DEBFILE(va("Adding world with map %s\n", mapname));
+
+	G_LoadWorld(mapname);
+}
+
 void SendWorldSwitch(INT32 worldnum, void *location, boolean nodetach)
 {
 	UINT8 buf[sizeof(INT32) + sizeof(UINT8) + (sizeof(fixed_t) * 3) + sizeof(angle_t)];
diff --git a/src/d_netcmd.h b/src/d_netcmd.h
index b0e04ec7fa8512ff7aeadd7abf70d5e3885a13ee..ae7ae5c214713b527a83fefaf541f1ad4718aac8 100644
--- a/src/d_netcmd.h
+++ b/src/d_netcmd.h
@@ -130,24 +130,25 @@ typedef enum
 	XD_SAY,         // 5
 	XD_MAP,         // 6
 	XD_EXITLEVEL,   // 7
-	XD_ADDFILE,     // 8
-	XD_ADDFOLDER,   // 9
-	XD_PAUSE,       // 10
-	XD_ADDPLAYER,   // 11
-	XD_TEAMCHANGE,  // 12
-	XD_CLEARSCORES, // 13
-	XD_SWITCHWORLD, // 14
-	XD_VERIFIED,    // 15
-	XD_RANDOMSEED,  // 16
-	XD_RUNSOC,      // 17
-	XD_REQADDFILE,  // 18
-	XD_REQADDFOLDER,// 19
-	XD_SETMOTD,     // 20
-	XD_SUICIDE,     // 21
-	XD_DEMOTED,     // 22
-	XD_LUACMD,      // 23
-	XD_LUAVAR,      // 24
-	XD_LUAFILE,     // 25
+	XD_NEWWORLD,    // 8
+	XD_SWITCHWORLD, // 9
+	XD_ADDFILE,     // 10
+	XD_ADDFOLDER,   // 11
+	XD_PAUSE,       // 12
+	XD_ADDPLAYER,   // 13
+	XD_TEAMCHANGE,  // 14
+	XD_CLEARSCORES, // 15
+	XD_VERIFIED,    // 16
+	XD_RANDOMSEED,  // 17
+	XD_RUNSOC,      // 18
+	XD_REQADDFILE,  // 19
+	XD_REQADDFOLDER,// 20
+	XD_SETMOTD,     // 21
+	XD_SUICIDE,     // 22
+	XD_DEMOTED,     // 23
+	XD_LUACMD,      // 24
+	XD_LUAVAR,      // 25
+	XD_LUAFILE,     // 26
 	MAXNETXCMD
 } netxcmd_t;
 
@@ -202,7 +203,8 @@ void D_SendPlayerConfig(void);
 void Command_ExitGame_f(void);
 void Command_Retry_f(void);
 void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
-void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean addworld, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
+void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
+void D_AddWorld(INT32 pmapnum);
 boolean IsPlayerAdmin(INT32 playernum);
 void SetAdminPlayer(INT32 playernum);
 void ClearAdminPlayers(void);
diff --git a/src/f_finale.c b/src/f_finale.c
index ccc1dfb84a976afce42177b290d85d68aa65b990..4a7da0cb53c0f8d47ae5fe93d5b799b654da74be 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -2429,13 +2429,13 @@ void F_StartTitleScreen(void)
 		if (!mapheaderinfo[gamemap-1])
 			P_AllocMapHeader(gamemap-1);
 
-		P_UnloadWorldList();
+		World_UnloadAll();
 
 		curmapheader = nextmapheader = mapheaderinfo[gamemap-1];
 		worldmapheader = curmapheader;
 		maptol = curmapheader->typeoflevel;
 
-		G_DoLoadLevel(&players[displayplayer], false, true);
+		G_DoLoadLevel(true);
 		if (!titlemap)
 			return;
 
@@ -3904,7 +3904,7 @@ void F_EndCutScene(void)
 	if (runningprecutscene)
 	{
 		if (server)
-			D_MapChange(gamemap, gametype, false, ultimatemode, precutresetplayer, 0, true, precutFLS);
+			D_MapChange(gamemap, gametype, ultimatemode, precutresetplayer, 0, true, precutFLS);
 	}
 	else
 	{
diff --git a/src/g_demo.c b/src/g_demo.c
index 470485a3a2eb86672c3dd1ca3816896b081e20a4..e51ef3e9dc1d847ea1360efe0ff5fd082cc8a6dc 100644
--- a/src/g_demo.c
+++ b/src/g_demo.c
@@ -1985,7 +1985,7 @@ void G_DoPlayDemo(char *defdemoname)
 	memset(playeringame,0,sizeof(playeringame));
 	playeringame[0] = true;
 	P_SetRandSeed(randseed);
-	G_InitNew(&players[0], G_BuildMapName(gamemap), false, false, true, true, false);
+	G_InitNew(G_BuildMapName(gamemap), false, true, true, false);
 
 	// Set color
 	players[0].skincolor = skins[players[0].skin].prefcolor;
diff --git a/src/g_game.c b/src/g_game.c
index e42ec8755ea160b1b2d105eba5801f6ccd06849f..270561eeee979fbe06a1b07ebde938cbb2842c7c 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -1794,7 +1794,7 @@ static void G_ResetCamera(INT32 playernum)
 //
 // G_DoLoadLevel
 //
-void G_DoLoadLevel(player_t *player, boolean addworld, boolean resetplayer)
+void G_DoLoadLevel(boolean resetplayer)
 {
 	INT32 i;
 
@@ -1826,29 +1826,18 @@ void G_DoLoadLevel(player_t *player, boolean addworld, boolean resetplayer)
 		titlemapinaction = TITLEMAP_OFF;
 
 	G_SetGamestate(GS_LEVEL);
-	if (player == &players[consoleplayer])
-		I_UpdateMouseGrab();
+	I_UpdateMouseGrab();
 
-	if (!addworld)
+	for (i = 0; i < MAXPLAYERS; i++)
 	{
-		for (i = 0; i < MAXPLAYERS; i++)
-		{
-			if (resetplayer || (playeringame[i] && players[i].playerstate == PST_DEAD))
-				players[i].playerstate = PST_REBORN;
-		}
-
-		P_UnloadWorldList();
+		if (resetplayer || (playeringame[i] && players[i].playerstate == PST_DEAD))
+			players[i].playerstate = PST_REBORN;
 	}
 
-	// Setup the level.
-	boolean success;
-	if (addworld)
-		success = P_LoadWorld(false);
-	else
-		success = P_LoadLevel(false, false); // this never returns false? (yes it can)
+	World_UnloadAll();
 
-	// fail so reset game stuff
-	if (!success)
+	// Setup the level.
+	if (!P_LoadLevel(false, false)) // this never returns false? (yes it can)
 	{
 		Command_ExitGame_f();
 		return;
@@ -1865,33 +1854,23 @@ void G_DoLoadLevel(player_t *player, boolean addworld, boolean resetplayer)
 	Z_CheckHeap(-2);
 #endif
 
-	if (!addworld)
+	// clear cmd building stuff
+	memset(gamekeydown, 0, sizeof (gamekeydown));
+	for (i = 0;i < JOYAXISSET; i++)
 	{
-		// clear cmd building stuff
-		memset(gamekeydown, 0, sizeof (gamekeydown));
-		for (i = 0;i < JOYAXISSET; i++)
-		{
-			joyxmove[i] = joyymove[i] = 0;
-			joy2xmove[i] = joy2ymove[i] = 0;
-		}
-		G_SetMouseDeltas(0, 0, 1);
-		G_SetMouseDeltas(0, 0, 2);
-
-		if (splitscreen)
-			G_ResetCamera(1);
+		joyxmove[i] = joyymove[i] = 0;
+		joy2xmove[i] = joy2ymove[i] = 0;
 	}
+	G_SetMouseDeltas(0, 0, 1);
+	G_SetMouseDeltas(0, 0, 2);
 
-	if (!addworld && player == &players[consoleplayer])
-	{
-		G_ResetCamera(consoleplayer);
+	if (splitscreen)
+		G_ResetCamera(1);
 
-		// clear hud messages remains (usually from game startup)
-		CON_ClearHUD();
-	}
+	G_ResetCamera(consoleplayer);
 
-	// change world back to yours, for consistency
-	if (addworld)
-		P_SetWorld(localworld);
+	// clear hud messages remains (usually from game startup)
+	CON_ClearHUD();
 }
 
 //
@@ -2753,9 +2732,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
 	p->playerstate = PST_LIVE;
 	p->panim = PA_IDLE; // standing animation
 
-	if (p->world)
-		((world_t *)p->world)->players++;
-
 	//if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there
 		//p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent
 
@@ -3292,7 +3268,7 @@ void G_DoReborn(INT32 playernum)
 		{
 			LUA_HookInt(gamemap, HOOK(MapChange));
 			titlecardforreload = true;
-			G_DoLoadLevel(&players[consoleplayer], false, true);
+			G_DoLoadLevel(true);
 			titlecardforreload = false;
 			if (metalrecording)
 				G_BeginMetal();
@@ -3360,8 +3336,11 @@ void G_AddPlayer(INT32 playernum)
 		}
 	}
 
-	if (worldlist) // Assume the player is on the first world
-		p->world = worldlist[0];
+	p->world = NULL;
+
+	// Let's just place the player in the first world
+	if (worldlist)
+		P_SwitchPlayerWorld(p, worldlist[0]);
 
 	p->playerstate = PST_REBORN;
 
@@ -4227,10 +4206,10 @@ static void G_DoWorldDone(void)
 	{
 		if (gametyperules & GTR_CAMPAIGN)
 			// don't reset player between maps
-			D_MapChange(nextmap+1, gametype, false, ultimatemode, false, 0, false, false);
+			D_MapChange(nextmap+1, gametype, ultimatemode, false, 0, false, false);
 		else
 			// resetplayer in match/chaos/tag/CTF/race for more equality
-			D_MapChange(nextmap+1, gametype, false, ultimatemode, true, 0, false, false);
+			D_MapChange(nextmap+1, gametype, ultimatemode, true, 0, false, false);
 	}
 
 	gameaction = ga_nothing;
@@ -4293,7 +4272,7 @@ static void G_DoContinued(void)
 	// Reset # of lives
 	pl->lives = (ultimatemode) ? 1 : startinglivesbalance[numgameovers];
 
-	D_MapChange(gamemap, gametype, false, ultimatemode, false, 0, false, false);
+	D_MapChange(gamemap, gametype, ultimatemode, false, 0, false, false);
 
 	gameaction = ga_nothing;
 }
@@ -4999,7 +4978,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, b
 	CV_StealthSetValue(&cv_playercolor, color);
 
 	if (mapname)
-		D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, false, pultmode, true, 1, false, FLS);
+		D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, pultmode, true, 1, false, FLS);
 }
 
 static void G_ResetPlayer(player_t *player, boolean pultmode, boolean FLS)
@@ -5036,9 +5015,7 @@ static void G_ResetPlayer(player_t *player, boolean pultmode, boolean FLS)
 // This is the map command interpretation something like Command_Map_f
 //
 // called at: map cmd execution, doloadgame, doplaydemo
-void G_InitNew(player_t *player,
-	const char *mapname, boolean addworld,
-	UINT8 pultmode, boolean resetplayer, boolean skipprecutscene, boolean FLS)
+void G_InitNew(const char *mapname, UINT8 pultmode, boolean resetplayer, boolean skipprecutscene, boolean FLS)
 {
 	INT32 i;
 
@@ -5062,11 +5039,8 @@ void G_InitNew(player_t *player,
 		numgameovers = tokenlist = token = sstimer = redscore = bluescore = lastmap = 0;
 		countdown = countdown2 = exitfadestarted = 0;
 
-		if (!addworld)
-		{
-			for (i = 0; i < MAXPLAYERS; i++)
-				G_ResetPlayer(&players[i], pultmode, FLS);
-		}
+		for (i = 0; i < MAXPLAYERS; i++)
+			G_ResetPlayer(&players[i], pultmode, FLS);
 
 		// Reset unlockable triggers
 		unlocktriggers = 0;
@@ -5093,15 +5067,8 @@ void G_InitNew(player_t *player,
 	if(!mapheaderinfo[gamemap-1])
 		P_AllocMapHeader(gamemap-1);
 
-	nextmapheader = mapheaderinfo[gamemap-1];
-
-	if (!addworld)
-	{
-		curmapheader = nextmapheader;
-		maptol = nextmapheader->typeoflevel;
-	}
-
-	worldmapheader = nextmapheader;
+	curmapheader = worldmapheader = nextmapheader = mapheaderinfo[gamemap-1];
+	maptol = nextmapheader->typeoflevel;
 
 	// Don't carry over custom music change to another map.
 	mapmusflags |= MUSIC_RELOADRESET;
@@ -5110,13 +5077,12 @@ void G_InitNew(player_t *player,
 	automapactive = false;
 	imcontinuing = false;
 
-	if (!addworld && ((gametyperules & GTR_CUTSCENES) && !skipprecutscene && nextmapheader->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene.
+	if ((gametyperules & GTR_CUTSCENES) && !skipprecutscene && nextmapheader->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES)) // Start a custom cutscene.
 		F_StartCustomCutscene(nextmapheader->precutscenenum-1, true, resetplayer, FLS);
 	else
-		G_DoLoadLevel(player, addworld, resetplayer);
+		G_DoLoadLevel(resetplayer);
 
-	// current world is hopefully the newly loaded world at this point
-	if (netgame && !addworld)
+	if (netgame)
 	{
 		char *title = G_BuildMapTitle(gamemap);
 
@@ -5130,6 +5096,42 @@ void G_InitNew(player_t *player,
 	}
 }
 
+boolean G_LoadWorld(const char *mapname)
+{
+	// Check if the map is actually valid.
+	if (W_CheckNumForName(mapname) == LUMPERROR)
+	{
+		CONS_Alert(CONS_ERROR, "G_LoadWorld: Internal game map '%s' not found\n", mapname);
+		return false;
+	}
+
+	INT16 mapnum = (INT16)M_MapNumber(mapname[3], mapname[4]); // get xx out of MAPxx
+
+	LUA_HookInt(mapnum, HOOK(MapChange));
+
+	// gamemap changed; we assume that its map header is always valid,
+	// so make it so
+	if(!mapheaderinfo[mapnum-1])
+		P_AllocMapHeader(mapnum-1);
+
+	nextmapheader = mapheaderinfo[mapnum-1];
+	worldmapheader = nextmapheader;
+
+	if (!P_LoadWorld(mapnum, false))
+	{
+		CONS_Alert(CONS_ERROR, "G_LoadWorld: Could not load map '%s'\n", mapname);
+		return false;
+	}
+
+#ifdef PARANOIA
+	Z_CheckHeap(-2);
+#endif
+
+	// change world back to yours, for consistency
+	P_SetWorld(localworld);
+
+	return true;
+}
 
 char *G_BuildMapTitle(INT32 mapnum)
 {
diff --git a/src/g_game.h b/src/g_game.h
index 3a4b3b4133425fd093619fbe7df8371c9d3672db..5550c8698662f3e57aedbfddcc62a77f939fef50 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -136,9 +136,7 @@ extern INT32 localaiming, localaiming2; // should be an angle_t but signed
 void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo);
 void G_DoReborn(INT32 playernum);
 void G_PlayerReborn(INT32 player, boolean betweenmaps);
-void G_InitNew(player_t *player,
-	const char *mapname, boolean addworld,
-	UINT8 pultmode, boolean resetplayer, boolean skipprecutscene, boolean FLS);
+void G_InitNew(const char *mapname, UINT8 pultmode, boolean resetplayer, boolean skipprecutscene, boolean FLS);
 char *G_BuildMapTitle(INT32 mapnum);
 
 struct searchdim
@@ -176,9 +174,11 @@ void G_SpawnPlayer(INT32 playernum);
 
 // Can be called by the startup code or M_Responder.
 // A normal game starts at map 1, but a warp test can start elsewhere
-void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar,
-	boolean SSSG, boolean FLS);
-void G_DoLoadLevel(player_t *player, boolean addworld, boolean resetplayer);
+void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar,boolean SSSG, boolean FLS);
+void G_DoLoadLevel(boolean resetplayer);
+
+boolean G_LoadWorld(const char *mapname);
+
 void G_StartTitleCard(void);
 void G_PreLevelTitleCard(void);
 boolean G_IsTitleCardAvailable(void);
diff --git a/src/m_menu.c b/src/m_menu.c
index cae75902b4dae9d26135ac01fab827609816924d..8d29a646c99ad641b907536085acb42bfa0bf00d 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -11594,7 +11594,7 @@ static void M_StartServer(INT32 choice)
 
 	if (!StartSplitScreenGame)
 	{
-		D_MapChange(cv_nextmap.value, cv_newgametype.value, false, false, 1, 1, false, false);
+		D_MapChange(cv_nextmap.value, cv_newgametype.value, false, 1, 1, false, false);
 		COM_BufAddText("dummyconsvar 1\n");
 	}
 	else // split screen
@@ -11606,7 +11606,7 @@ static void M_StartServer(INT32 choice)
 			splitscreen = true;
 			SplitScreen_OnChange();
 		}
-		D_MapChange(cv_nextmap.value, cv_newgametype.value, false, false, 1, 1, false, false);
+		D_MapChange(cv_nextmap.value, cv_newgametype.value, false, 1, 1, false, false);
 	}
 
 	M_ClearMenus(true);
diff --git a/src/p_saveg.c b/src/p_saveg.c
index daa388f3dbc2156042b4898b57712596774b100f..568ff1b2af320690714b9104a48a8047fa5bf383 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -4365,7 +4365,7 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
 	if (READUINT32(save_p) != ARCHIVEBLOCK_MISC)
 		I_Error("Bad $$$.sav at archive block Misc");
 
-	P_UnloadWorldList();
+	World_UnloadAll();
 	if (reloading)
 		gametic = READUINT32(save_p);
 
@@ -4920,12 +4920,12 @@ static void P_NetUnArchiveWorlds(void)
 	// Unarchive each world
 	for (INT32 i = 0; i < worldcount; i++)
 	{
-		gamemap = READINT16(save_p);
+		INT16 mapnum = READINT16(save_p);
 
 		// Don't load the first world (because it already is loaded at this point)
 		if (i != 0)
 		{
-			if (!P_LoadWorld(true))
+			if (!P_LoadWorld(mapnum, true))
 				I_Error("P_NetUnArchiveWorlds: failed loading world");
 		}
 
diff --git a/src/p_setup.c b/src/p_setup.c
index baf5c093dd43351abed412875dc3ba31219f6957..d8b34844335093840c3f07078f330068b1e47c44 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -7562,7 +7562,7 @@ static void P_InitGametype(boolean addworld)
 static world_t *P_InitWorldFromMap(INT16 mapnumber, mapheader_t *mapheader, boolean addworld, boolean fromnetsave)
 {
 	world_t *curworld = world;
-	world_t *w = P_InitNewWorld();
+	world_t *w = World_PushNew(mapnumber);
 
 	w->loading = true;
 
@@ -7614,7 +7614,7 @@ static world_t *P_InitWorldFromMap(INT16 mapnumber, mapheader_t *mapheader, bool
 	P_InitSlopes();
 
 	if (!P_LoadMapFromFile(maplumpnum))
-		return false;
+		return NULL;
 
 	// init anything that P_SpawnSlopes/P_SpawnMapThings needs to know
 	P_InitSpecials();
@@ -7923,7 +7923,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
 	return true;
 }
 
-boolean P_LoadWorld(boolean fromnetsave)
+boolean P_LoadWorld(INT16 mapnum, boolean fromnetsave)
 {
 	// Initialize sector node list.
 	P_Initsecnode();
@@ -7943,12 +7943,14 @@ boolean P_LoadWorld(boolean fromnetsave)
 		wipestyleflags = 0;
 	}
 
-	world_t *w = P_InitWorldFromMap(gamemap, worldmapheader, true, fromnetsave);
+	world_t *w = P_InitWorldFromMap(mapnum, worldmapheader, true, fromnetsave);
 	if (w == NULL)
-		I_Error("Map %s not found.\n", G_BuildMapName(gamemap));
+		return false;
 
 	P_FinishMapLoad(fromnetsave);
 
+	P_FindEmerald(world);
+
 	return true;
 }
 
diff --git a/src/p_setup.h b/src/p_setup.h
index b293d4e65d338a8b33a654785e2728b90a0d3fa3..6a385f87552ec6a1875059e2418917ca3a0e3ede 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -98,7 +98,7 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
 #endif
 void P_RespawnThings(void);
 boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
-boolean P_LoadWorld(boolean fromnetsave);
+boolean P_LoadWorld(INT16 mapnum, boolean fromnetsave);
 
 boolean P_AddWadFile(const char *wadfilename);
 boolean P_AddFolder(const char *folderpath);
diff --git a/src/p_world.c b/src/p_world.c
index 503100e278e6bf07ece770ca079fa843c670b985..a9e66d05bdc1c0879908f9386797b40f342f58d5 100644
--- a/src/p_world.c
+++ b/src/p_world.c
@@ -54,15 +54,15 @@ world_t **worldlist = NULL;
 INT32 numworlds = 0;
 
 //
-// Initializes a world.
+// Creates a world.
 //
-world_t *P_InitWorld(void)
+world_t *World_Create(INT16 mapnum)
 {
 	world_t *w = Z_Calloc(sizeof(world_t), PU_STATIC, NULL);
-	w->gamemap = gamemap;
-	if (!mapheaderinfo[gamemap-1])
-		P_AllocMapHeader(gamemap-1);
-	w->header = mapheaderinfo[gamemap-1];
+	w->gamemap = mapnum;
+	if (!mapheaderinfo[mapnum-1])
+		P_AllocMapHeader(mapnum-1);
+	w->header = mapheaderinfo[mapnum-1];
 	w->thlist = Z_Calloc(sizeof(thinker_t) * NUM_THINKERLISTS, PU_STATIC, NULL);
 	P_InitCachedActions(w);
 	return w;
@@ -71,10 +71,10 @@ world_t *P_InitWorld(void)
 //
 // Initializes a new world, inserting it into the world list.
 //
-world_t *P_InitNewWorld(void)
+world_t *World_PushNew(INT16 mapnum)
 {
 	worldlist = Z_Realloc(worldlist, (numworlds + 1) * sizeof(void *), PU_STATIC, NULL);
-	worldlist[numworlds] = P_InitWorld();
+	worldlist[numworlds] = World_Create(mapnum);
 
 	world_t *w = worldlist[numworlds];
 
@@ -173,7 +173,7 @@ void P_DetachPlayerWorld(player_t *player)
 
 	player->world = NULL;
 
-	if (player->mo && !P_MobjWasRemoved(player->mo))
+	if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->world != NULL)
 	{
 		R_RemoveMobjInterpolator(player->mo);
 		player->mo->world = NULL;
@@ -189,7 +189,7 @@ void P_SwitchPlayerWorld(player_t *player, world_t *newworld)
 
 	player->world = newworld;
 
-	if (player->mo && !P_MobjWasRemoved(player->mo))
+	if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->world == NULL)
 	{
 		player->mo->world = newworld;
 		R_AddMobjInterpolator(player->mo);
@@ -220,7 +220,7 @@ void P_RoamIntoWorld(player_t *player, INT32 mapnum)
 	else if (w)
 		P_SwitchWorld(player, w, NULL);
 	else
-		D_MapChange(mapnum, gametype, true, false, false, 0, false, false);
+		D_AddWorld(mapnum);
 }
 
 boolean P_TransferCarriedPlayers(player_t *player, world_t *w)
@@ -452,7 +452,7 @@ static void P_UnloadSectorAttachments(sector_t *s, size_t ns)
 //
 // Unloads a world.
 //
-void P_UnloadWorld(world_t *w)
+void World_Delete(world_t *w)
 {
 	if (w == NULL)
 		return;
@@ -478,7 +478,7 @@ void P_UnloadWorld(world_t *w)
 //
 // Unloads all worlds.
 //
-void P_UnloadWorldList(void)
+void World_UnloadAll(void)
 {
 	INT32 i;
 
@@ -501,7 +501,7 @@ void P_UnloadWorldList(void)
 		if (w == NULL)
 			continue;
 
-		P_UnloadWorld(w);
+		World_Delete(w);
 	}
 
 	Z_Free(worldlist);
@@ -525,26 +525,6 @@ void P_UnloadWorldList(void)
 	world = localworld = viewworld = NULL;
 }
 
-//
-// Unloads a player.
-//
-void P_UnloadWorldPlayer(player_t *player)
-{
-	P_DetachPlayerWorld(player);
-
-	if (player->followmobj)
-	{
-		P_RemoveMobj(player->followmobj);
-		P_SetTarget(&player->followmobj, NULL);
-	}
-
-	if (player->mo)
-	{
-		P_RemoveMobj(player->mo);
-		P_SetTarget(&player->mo, NULL);
-	}
-}
-
 boolean P_MobjIsConnected(mobj_t *mobj1, mobj_t *mobj2)
 {
 	return mobj2 && !P_MobjWasRemoved(mobj2) && P_GetMobjWorld(mobj1) == P_GetMobjWorld(mobj2);
diff --git a/src/p_world.h b/src/p_world.h
index 94da9736e53e728eb7619ed4258597e39076ace2..6ce4f86f1500dc5ae544cbda468306a91e21de3d 100644
--- a/src/p_world.h
+++ b/src/p_world.h
@@ -163,12 +163,10 @@ typedef struct
 	angle_t angle;
 } location_t;
 
-world_t *P_InitWorld(void);
-world_t *P_InitNewWorld(void);
-
-void P_UnloadWorld(world_t *w);
-void P_UnloadWorldList(void);
-void P_UnloadWorldPlayer(player_t *player);
+world_t *World_Create(INT16 mapnum);
+world_t *World_PushNew(INT16 mapnum);
+void World_Delete(world_t *w);
+void World_UnloadAll(void);
 
 void P_SetGameWorld(world_t *w);
 void P_SetViewWorld(world_t *w);