diff --git a/src/d_main.c b/src/d_main.c
index 7a8a85f255e96db1f7e4f5ad3c86963131df7325..d1936d6bb1c75b98c26201d450ba60abca336433 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -301,7 +301,7 @@ static void D_Display(void)
 		if (rendermode != render_none)
 		{
 			// Fade to black first
-			if (gamestate != GS_LEVEL // fades to black on its own timing, always
+			if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)) // fades to black on its own timing, always
 			 && wipedefs[wipedefindex] != UINT8_MAX)
 			{
 				F_WipeStartScreen();
@@ -317,6 +317,12 @@ static void D_Display(void)
 	// do buffered drawing
 	switch (gamestate)
 	{
+		case GS_TITLESCREEN:
+			if (!titlemapinaction) {
+				F_TitleScreenDrawer();
+				break;
+			}
+			// Intentional fall-through
 		case GS_LEVEL:
 			if (!gametic)
 				break;
@@ -365,10 +371,6 @@ static void D_Display(void)
 			HU_Drawer();
 			break;
 
-		case GS_TITLESCREEN:
-			F_TitleScreenDrawer();
-			break;
-
 		case GS_WAITINGPLAYERS:
 			// The clientconnect drawer is independent...
 		case GS_DEDICATEDSERVER:
@@ -378,9 +380,10 @@ static void D_Display(void)
 
 	// clean up border stuff
 	// see if the border needs to be initially drawn
-	if (gamestate == GS_LEVEL)
+	if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))
 	{
 		// draw the view directly
+
 		if (!automapactive && !dedicated && cv_renderview.value)
 		{
 			if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD)
@@ -438,9 +441,13 @@ static void D_Display(void)
 			lastdraw = false;
 		}
 
-		ST_Drawer();
-
-		HU_Drawer();
+		if (gamestate == GS_LEVEL)
+		{
+			ST_Drawer();
+			HU_Drawer();
+		}
+		else
+			F_TitleScreenDrawer();
 	}
 
 	// change gamma if needed
@@ -680,6 +687,9 @@ void D_AdvanceDemo(void)
 void D_StartTitle(void)
 {
 	INT32 i;
+
+	S_StopMusic();
+
 	if (netgame)
 	{
 		if (gametype == GT_COOP)
@@ -1345,6 +1355,19 @@ void D_SRB2Main(void)
 		ultimatemode = true;
 	}
 
+	// rei/miru: bootmap (Idea: starts the game on a predefined map)
+	if (bootmap && !(M_CheckParm("-warp") && M_IsNextParm()))
+	{
+		pstartmap = bootmap;
+
+		if (pstartmap < 1 || pstartmap > NUMMAPS)
+			I_Error("Cannot warp to map %d (out of range)\n", pstartmap);
+		else
+		{
+			autostart = true;
+		}
+	}
+
 	if (autostart || netgame || M_CheckParm("+connect") || M_CheckParm("-connect"))
 	{
 		gameaction = ga_nothing;
diff --git a/src/dehacked.c b/src/dehacked.c
index 719476543d95d99aebfdceb2d81957074a0d917d..89f44cb3b6f310dc139017e4dfcb37c322c8c445 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -77,6 +77,8 @@ boolean deh_loaded = false;
 static int dbg_line;
 
 static boolean gamedataadded = false;
+static boolean titlechanged = false;
+static boolean introchanged = false;
 
 ATTRINLINE static FUNCINLINE char myfget_color(MYFILE *f)
 {
@@ -2667,14 +2669,38 @@ static void readmaincfg(MYFILE *f)
 				// range check, you morons.
 				if (introtoplay > 128)
 					introtoplay = 128;
+				introchanged = true;
 			}
 			else if (fastcmp(word, "LOOPTITLE"))
 			{
 				looptitle = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y');
+				titlechanged = true;
+			}
+			else if (fastcmp(word, "TITLEMAP"))
+			{
+				// Support using the actual map name,
+				// i.e., Level AB, Level FZ, etc.
+
+				// Convert to map number
+				if (word2[0] >= 'A' && word2[0] <= 'Z')
+					value = M_MapNumber(word2[0], word2[1]);
+				else
+					value = get_number(word2);
+
+				DEH_WriteUndoline(word, va("%d", titlemap), UNDO_NONE);
+				titlemap = (INT16)value;
+				titlechanged = true;
+			}
+			else if (fastcmp(word, "HIDETITLEPICS"))
+			{
+				DEH_WriteUndoline(word, va("%d", hidetitlepics), UNDO_NONE);
+				hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y');
+				titlechanged = true;
 			}
 			else if (fastcmp(word, "TITLESCROLLSPEED"))
 			{
 				titlescrollspeed = get_number(word2);
+				titlechanged = true;
 			}
 			else if (fastcmp(word, "CREDITSCUTSCENE"))
 			{
@@ -2690,14 +2716,17 @@ static void readmaincfg(MYFILE *f)
 			else if (fastcmp(word, "NUMDEMOS"))
 			{
 				numDemos = (UINT8)get_number(word2);
+				titlechanged = true;
 			}
 			else if (fastcmp(word, "DEMODELAYTIME"))
 			{
 				demoDelayTime = get_number(word2);
+				titlechanged = true;
 			}
 			else if (fastcmp(word, "DEMOIDLETIME"))
 			{
 				demoIdleTime = get_number(word2);
+				titlechanged = true;
 			}
 			else if (fastcmp(word, "USE1UPSOUND"))
 			{
@@ -2731,14 +2760,32 @@ static void readmaincfg(MYFILE *f)
 				strlcat(savegamename, "%u.ssg", sizeof(savegamename));
 
 				gamedataadded = true;
+				titlechanged = true;
 			}
 			else if (fastcmp(word, "RESETDATA"))
 			{
 				P_ResetData(value);
+				titlechanged = true;
 			}
 			else if (fastcmp(word, "CUSTOMVERSION"))
 			{
 				strlcpy(customversionstring, word2, sizeof (customversionstring));
+				//titlechanged = true;
+			}
+			else if (fastcmp(word, "BOOTMAP"))
+			{
+				// Support using the actual map name,
+				// i.e., Level AB, Level FZ, etc.
+
+				// Convert to map number
+				if (word2[0] >= 'A' && word2[0] <= 'Z')
+					value = M_MapNumber(word2[0], word2[1]);
+				else
+					value = get_number(word2);
+
+				DEH_WriteUndoline(word, va("%d", bootmap), UNDO_NONE);
+				bootmap = (INT16)value;
+				//titlechanged = true;
 			}
 			else
 				deh_warning("Maincfg: unknown word '%s'", word);
@@ -2935,7 +2982,7 @@ static void DEH_LoadDehackedFile(MYFILE *f)
 
 	deh_num_warning = 0;
 
-	gamedataadded = false;
+	gamedataadded = titlechanged = introchanged = false;
 
 	// it doesn't test the version of SRB2 and version of dehacked file
 	dbg_line = -1; // start at -1 so the first line is 0.
@@ -3236,6 +3283,14 @@ static void DEH_LoadDehackedFile(MYFILE *f)
 	if (gamedataadded)
 		G_LoadGameData();
 
+	if (gamestate == GS_TITLESCREEN)
+	{
+		if (introchanged)
+			COM_BufAddText("playintro");
+		else if (titlechanged)
+			COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed
+	}
+
 	dbg_line = -1;
 	if (deh_num_warning)
 	{
@@ -8119,6 +8174,12 @@ static inline int lib_getenum(lua_State *L)
 	} else if (fastcmp(word,"paused")) {
 		lua_pushboolean(L, paused);
 		return 1;
+	} else if (fastcmp(word,"titlemap")) {
+		lua_pushinteger(L, titlemap);
+		return 1;
+	} else if (fastcmp(word,"titlemapinaction")) {
+		lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
+		return 1;
 	} else if (fastcmp(word,"gametype")) {
 		lua_pushinteger(L, gametype);
 		return 1;
diff --git a/src/doomstat.h b/src/doomstat.h
index a24bad79d73dc21dbd1b7b5b63728e4efb4862f0..04930eff516d6876590a1b8de9c1a2e1d6adb64e 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -125,6 +125,10 @@ extern INT16 spstage_start;
 extern INT16 sstage_start;
 extern INT16 sstage_end;
 
+extern INT16 titlemap;
+extern boolean hidetitlepics;
+extern INT16 bootmap; //bootmap for loading a map on startup
+
 extern boolean looptitle;
 extern boolean useNightsSS;
 
diff --git a/src/f_finale.c b/src/f_finale.c
index db497daf7f26d59057e24c32f27c45fb521c73de..89df1446774922fe257d827985e15334b7374c2c 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -31,11 +31,18 @@
 #include "m_random.h"
 #include "y_inter.h"
 #include "m_cond.h"
+#include "p_local.h"
+#include "p_setup.h"
+
+#ifdef HAVE_BLUA
+#include "lua_hud.h"
+#endif
 
 // Stage of animation:
 // 0 = text, 1 = art screen
 static INT32 finalecount;
 INT32 titlescrollspeed = 80;
+UINT8 titlemapinaction = TITLEMAP_OFF;
 
 static INT32 timetonext; // Delay between screen changes
 static INT32 continuetime; // Short delay when continuing
@@ -217,17 +224,19 @@ static void F_SkyScroll(INT32 scrollspeed)
 {
 	INT32 scrolled, x, mx, fakedwidth;
 	patch_t *pat;
+	INT16 patwidth;
 
 	pat = W_CachePatchName("TITLESKY", PU_CACHE);
 
-	animtimer = ((finalecount*scrollspeed)/16) % SHORT(pat->width);
+	patwidth = SHORT(pat->width);
+	animtimer = ((finalecount*scrollspeed)/16 + patwidth) % patwidth;
 
 	fakedwidth = vid.width / vid.dupx;
 
 	if (rendermode == render_soft)
 	{ // if only hardware rendering could be this elegant and complete
-		scrolled = (SHORT(pat->width) - animtimer) - 1;
-		for (x = 0, mx = scrolled; x < fakedwidth; x++, mx = (mx+1)%SHORT(pat->width))
+		scrolled = (patwidth - animtimer) - 1;
+		for (x = 0, mx = scrolled; x < fakedwidth; x++, mx = (mx+1)%patwidth)
 			F_DrawPatchCol(x, pat, mx);
 	}
 #ifdef HWRENDER
@@ -235,8 +244,8 @@ static void F_SkyScroll(INT32 scrollspeed)
 	{ // if only software rendering could be this simple and retarded
 		scrolled = animtimer;
 		if (scrolled > 0)
-			V_DrawScaledPatch(scrolled - SHORT(pat->width), 0, 0, pat);
-		for (x = 0; x < fakedwidth; x += SHORT(pat->width))
+			V_DrawScaledPatch(scrolled - patwidth, 0, 0, pat);
+		for (x = 0; x < fakedwidth; x += patwidth)
 			V_DrawScaledPatch(x + scrolled, 0, 0, pat);
 	}
 #endif
@@ -278,6 +287,8 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
 
 void F_StartIntro(void)
 {
+	S_StopMusic();
+
 	if (introtoplay)
 	{
 		if (!cutscenes[introtoplay - 1])
@@ -998,7 +1009,7 @@ static const char *credits[] = {
 	"",
 	"\1Sprite Artists",
 	"Odi \"Iceman404\" Atunzu",
-	"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D:
+	"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D:
 	"Jim \"MotorRoach\" DeMello",
 	"Desmond \"Blade\" DesJardins",
 	"Sherman \"CoatRack\" DesJardins",
@@ -1415,17 +1426,72 @@ void F_GameEndTicker(void)
 // ==============
 void F_StartTitleScreen(void)
 {
+	S_ChangeMusicInternal("_title", looptitle);
+
 	if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
 		finalecount = 0;
 	else
 		wipegamestate = GS_TITLESCREEN;
+
+	if (titlemap)
+	{
+		mapthing_t *startpos;
+
+		gamestate_t prevwipegamestate = wipegamestate;
+		titlemapinaction = TITLEMAP_LOADING;
+		gamemap = titlemap;
+
+		if (!mapheaderinfo[gamemap-1])
+			P_AllocMapHeader(gamemap-1);
+
+		maptol = mapheaderinfo[gamemap-1]->typeoflevel;
+		globalweather = mapheaderinfo[gamemap-1]->weather;
+
+		G_DoLoadLevel(true);
+		if (!titlemap)
+			return;
+
+		players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater)
+
+		// Set Default Position
+		if (playerstarts[0])
+			startpos = playerstarts[0];
+		else if (deathmatchstarts[0])
+			startpos = deathmatchstarts[0];
+		else
+			startpos = NULL;
+
+		if (startpos)
+		{
+			camera.x = startpos->x << FRACBITS;
+			camera.y = startpos->y << FRACBITS;
+			camera.subsector = R_PointInSubsector(camera.x, camera.y);
+			camera.z = camera.subsector->sector->floorheight + ((startpos->options >> ZSHIFT) << FRACBITS);
+			camera.angle = (startpos->angle % 360)*ANG1;
+			camera.aiming = 0;
+		}
+		else
+		{
+			camera.x = camera.y = camera.z = camera.angle = camera.aiming = 0;
+			camera.subsector = NULL; // toast is filthy too
+		}
+
+		camera.chase = true;
+		camera.height = 0;
+
+		wipegamestate = prevwipegamestate;
+	}
+	else
+	{
+		titlemapinaction = TITLEMAP_OFF;
+		gamemap = 1; // g_game.c
+		CON_ClearHUD();
+	}
+
 	G_SetGamestate(GS_TITLESCREEN);
-	CON_ClearHUD();
 
 	// IWAD dependent stuff.
 
-	S_ChangeMusicInternal("_title", looptitle);
-
 	animtimer = 0;
 
 	demoDelayLeft = demoDelayTime;
@@ -1455,12 +1521,21 @@ void F_TitleScreenDrawer(void)
 		return; // We likely came here from retrying. Don't do a damn thing.
 
 	// Draw that sky!
-	F_SkyScroll(titlescrollspeed);
+	if (!titlemapinaction)
+		F_SkyScroll(titlescrollspeed);
 
 	// Don't draw outside of the title screewn, or if the patch isn't there.
 	if (!ttwing || (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS))
 		return;
 
+	// rei|miru: use title pics?
+	if (hidetitlepics)
+#ifdef HAVE_BLUA
+		goto luahook;
+#else
+		return;
+#endif
+
 	V_DrawScaledPatch(30, 14, 0, ttwing);
 
 	if (finalecount < 57)
@@ -1497,6 +1572,11 @@ void F_TitleScreenDrawer(void)
 	}
 
 	V_DrawScaledPatch(48, 142, 0,ttbanner);
+
+#ifdef HAVE_BLUA
+luahook:
+	LUAh_TitleHUD();
+#endif
 }
 
 // (no longer) De-Demo'd Title Screen
@@ -1509,6 +1589,46 @@ void F_TitleScreenTicker(boolean run)
 	if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN)
 		return;
 
+	// Execute the titlemap camera settings
+	if (titlemapinaction)
+	{
+		thinker_t *th;
+		mobj_t *mo2;
+		mobj_t *cameraref = NULL;
+
+		for (th = thinkercap.next; th != &thinkercap; th = th->next)
+		{
+			if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
+				continue;
+
+			mo2 = (mobj_t *)th;
+
+			 if (!mo2)
+				continue;
+
+			if (mo2->type != MT_ALTVIEWMAN)
+				continue;
+
+			cameraref = mo2;
+			break;
+		}
+
+		if (cameraref)
+		{
+			camera.x = cameraref->x;
+			camera.y = cameraref->y;
+			camera.z = cameraref->z;
+			camera.angle = cameraref->angle;
+			camera.aiming = cameraref->cusval;
+			camera.subsector = cameraref->subsector;
+		}
+		else
+		{
+			// Default behavior: Do a lil' camera spin if a title map is loaded;
+			camera.angle += titlescrollspeed*ANG1/64;
+		}
+	}
+
 	// no demos to play? or, are they disabled?
 	if (!cv_rollingdemos.value || !numDemos)
 		return;
diff --git a/src/f_finale.h b/src/f_finale.h
index 1f23643bec2bd52a91cd3477ded284eb2a842484..aadc64ad08e8abb9547155c8ada4420b49468146 100644
--- a/src/f_finale.h
+++ b/src/f_finale.h
@@ -62,6 +62,15 @@ void F_ContinueDrawer(void);
 
 extern INT32 titlescrollspeed;
 
+typedef enum
+{
+	TITLEMAP_OFF = 0,
+	TITLEMAP_LOADING,
+	TITLEMAP_RUNNING
+} titlemap_enum;
+
+extern UINT8 titlemapinaction;
+
 //
 // WIPE
 //
diff --git a/src/g_game.c b/src/g_game.c
index e996938ab30ac44cc2d655406e8008e46aaca748..96908de739cd4fdbac47b67bc66fbf65bea5174a 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -121,6 +121,10 @@ INT16 spstage_start;
 INT16 sstage_start;
 INT16 sstage_end;
 
+INT16 titlemap = 0;
+boolean hidetitlepics = false;
+INT16 bootmap; //bootmap for loading a map on startup
+
 boolean looptitle = false;
 boolean useNightsSS = false;
 
@@ -1633,6 +1637,21 @@ void G_DoLoadLevel(boolean resetplayer)
 	if (gamestate == GS_INTERMISSION)
 		Y_EndIntermission();
 
+	// cleanup
+	if (titlemapinaction == TITLEMAP_LOADING)
+	{
+		if (W_CheckNumForName(G_BuildMapName(gamemap)) == LUMPERROR)
+		{
+			titlemap = 0; // let's not infinite recursion ok
+			Command_ExitGame_f();
+			return;
+		}
+
+		titlemapinaction = TITLEMAP_RUNNING;
+	}
+	else
+		titlemapinaction = TITLEMAP_OFF;
+
 	G_SetGamestate(GS_LEVEL);
 
 	for (i = 0; i < MAXPLAYERS; i++)
@@ -1642,7 +1661,7 @@ void G_DoLoadLevel(boolean resetplayer)
 	}
 
 	// Setup the level.
-	if (!P_SetupLevel(false))
+	if (!P_SetupLevel(false)) // this never returns false?
 	{
 		// fail so reset game stuff
 		Command_ExitGame_f();
@@ -1991,6 +2010,7 @@ void G_Ticker(boolean run)
 			break;
 
 		case GS_TITLESCREEN:
+			if (titlemapinaction) P_Ticker(run); // then intentionally fall through
 		case GS_WAITINGPLAYERS:
 			F_TitleScreenTicker(run);
 			break;
diff --git a/src/lua_hud.h b/src/lua_hud.h
index ba0a1d8941deff4c5b19e40cae1368c19ad86b18..beaca7883e4425818539cbd9d0866e4e6cf3b8cc 100644
--- a/src/lua_hud.h
+++ b/src/lua_hud.h
@@ -42,3 +42,4 @@ boolean LUA_HudEnabled(enum hud option);
 
 void LUAh_GameHUD(player_t *stplyr);
 void LUAh_ScoresHUD(void);
+void LUAh_TitleHUD(void);
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 8175f1b9beacb2ac9e6920a66922c125d474500d..68a69cd1d2934e3af83f24c804aad7368b6f7359 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -88,11 +88,13 @@ static const char *const patch_opt[] = {
 
 enum hudhook {
 	hudhook_game = 0,
-	hudhook_scores
+	hudhook_scores,
+	hudhook_title
 };
 static const char *const hudhook_opt[] = {
 	"game",
 	"scores",
+	"title",
 	NULL};
 
 // alignment types for v.drawString
@@ -808,6 +810,9 @@ int LUA_HudLib(lua_State *L)
 
 		lua_newtable(L);
 		lua_rawseti(L, -2, 3); // HUD[2] = scores rendering functions array
+
+		lua_newtable(L);
+		lua_rawseti(L, -2, 4); // HUD[3] = title rendering functions array
 	lua_setfield(L, LUA_REGISTRYINDEX, "HUD");
 
 	luaL_newmetatable(L, META_HUDINFO);
@@ -920,4 +925,29 @@ void LUAh_ScoresHUD(void)
 	hud_running = false;
 }
 
+void LUAh_TitleHUD(void)
+{
+	if (!gL || !(hudAvailable & (1<<hudhook_title)))
+		return;
+
+	hud_running = true;
+	lua_pop(gL, -1);
+
+	lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
+	I_Assert(lua_istable(gL, -1));
+	lua_rawgeti(gL, -1, 4); // HUD[4] = rendering funcs
+	I_Assert(lua_istable(gL, -1));
+
+	lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
+	I_Assert(lua_istable(gL, -1));
+	lua_remove(gL, -3); // pop HUD
+	lua_pushnil(gL);
+	while (lua_next(gL, -3) != 0) {
+		lua_pushvalue(gL, -3); // graphics library (HUD[1])
+		LUA_Call(gL, 1);
+	}
+	lua_pop(gL, -1);
+	hud_running = false;
+}
+
 #endif
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 8f9c44fdbf5789995e83f582f155173dd48b5740..c201830b0276e3c65d8baa440f82d9f2bf3d79a5 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -34,6 +34,7 @@
 #ifdef ESLOPE
 #include "p_slopes.h"
 #endif
+#include "f_finale.h"
 
 // protos.
 static CV_PossibleValue_t viewheight_cons_t[] = {{16, "MIN"}, {56, "MAX"}, {0, NULL}};
@@ -8415,6 +8416,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 #endif
 	switch (mobj->type)
 	{
+		case MT_ALTVIEWMAN:
+			if (titlemapinaction) mobj->flags &= ~MF_NOTHINK;
+			break;
 		case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE:
 			mobj->fuse = mobj->info->mass;
 			break;
diff --git a/src/p_setup.c b/src/p_setup.c
index 9c4bede7474571667eff241d2736e683418ea46b..20c212212c420fb3f54dea2bba1822abab3f0c5c 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2667,7 +2667,9 @@ boolean P_SetupLevel(boolean skipprecip)
 
 	// As oddly named as this is, this handles music only.
 	// We should be fine starting it here.
-	S_Start();
+	/// ... as long as this isn't a titlemap transition, that is
+	if (!titlemapinaction)
+		S_Start();
 
 	// Let's fade to black here
 	// But only if we didn't do the special stage wipe
@@ -2681,7 +2683,7 @@ boolean P_SetupLevel(boolean skipprecip)
 	}
 
 	// Print "SPEEDING OFF TO [ZONE] [ACT 1]..."
-	if (rendermode != render_none)
+	if (!titlemapinaction && rendermode != render_none)
 	{
 		// Don't include these in the fade!
 		char tx[64];
diff --git a/src/p_user.c b/src/p_user.c
index 09cafa0b34ad2d914a6b74416e82edc48379d529..956f6fdd7447f44d6a4c74f171c354769bae2be3 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -165,7 +165,7 @@ fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move)
 boolean P_AutoPause(void)
 {
 	// Don't pause even on menu-up or focus-lost in netgames or record attack
-	if (netgame || modeattacking)
+	if (netgame || modeattacking || gamestate == GS_TITLESCREEN)
 		return false;
 
 	return (menuactive || window_notinfocus);
diff --git a/src/r_main.c b/src/r_main.c
index c998a7d93e3eef39addb34b9e39b5a5f70880c75..cabefed14e7d3714bccd4a57c03925e549b01979 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -914,7 +914,7 @@ void R_SetupFrame(player_t *player, boolean skybox)
 		chasecam = (cv_chasecam.value != 0);
 	}
 
-	if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD)
+	if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN)
 		chasecam = true; // force chasecam on
 	else if (player->spectator) // no spectator chasecam
 		chasecam = false; // force chasecam off
diff --git a/src/r_sky.c b/src/r_sky.c
index 5162518cba3f4de3d4461700817b916cd1bc9bf9..898424a9925d1f1fadb89f208eaf4c4a6d9d88f8 100644
--- a/src/r_sky.c
+++ b/src/r_sky.c
@@ -64,10 +64,6 @@ void R_SetupSkyDraw(void)
 	// the horizon line in a 256x128 sky texture
 	skytexturemid = (textures[skytexture]->height/2)<<FRACBITS;
 
-	// get the right drawer, it was set by screen.c, depending on the
-	// current video mode bytes per pixel (quick fix)
-	wallcolfunc = walldrawerfunc;
-
 	R_SetSkyScale();
 }
 
diff --git a/src/screen.c b/src/screen.c
index 2e3d2e0f419545492d1660e4479b3bf335edfa92..8c1811d5d9d0d1122441b41583587ed879ad54eb 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -173,6 +173,9 @@ void SCR_SetMode(void)
 	if (SCR_IsAspectCorrect(vid.width, vid.height))
 		CONS_Alert(CONS_WARNING, M_GetText("Resolution is not aspect-correct!\nUse a multiple of %dx%d\n"), BASEVIDWIDTH, BASEVIDHEIGHT);
 #endif*/
+
+	wallcolfunc = walldrawerfunc;
+
 	// set the apprpriate drawer for the sky (tall or INT16)
 	setmodeneeded = 0;
 }