diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 43f04bae3..12aeac6ae 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -2985,6 +2985,7 @@ static void Command_Addfile(void)
 	XBOXSTATIC char buf[256];
 	char *buf_p = buf;
 	INT32 i;
+	int musiconly; // W_VerifyNMUSlumps isn't boolean
 
 	if (COM_Argc() != 2)
 	{
@@ -2999,7 +3000,9 @@ static void Command_Addfile(void)
 		if (!isprint(fn[i]) || fn[i] == ';')
 			return;
 
-	if (!W_VerifyNMUSlumps(fn))
+	musiconly = W_VerifyNMUSlumps(fn);
+
+	if (!musiconly)
 	{
 		// ... But only so long as they contain nothing more then music and sprites.
 		if (netgame && !(server || adminplayer == consoleplayer))
@@ -3011,7 +3014,7 @@ static void Command_Addfile(void)
 	}
 
 	// Add file on your client directly if it is trivial, or you aren't in a netgame.
-	if (!(netgame || multiplayer) || W_VerifyNMUSlumps(fn))
+	if (!(netgame || multiplayer) || musiconly)
 	{
 		P_AddWadFile(fn, NULL);
 		return;
@@ -3031,9 +3034,7 @@ static void Command_Addfile(void)
 #else
 		FILE *fhandle;
 
-		fhandle = fopen(fn, "rb");
-
-		if (fhandle)
+		if ((fhandle = W_OpenWadFile(&fn, true)) != NULL)
 		{
 			tic_t t = I_GetTime();
 			CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn);
@@ -3041,11 +3042,8 @@ static void Command_Addfile(void)
 			CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE);
 			fclose(fhandle);
 		}
-		else
-		{
-			CONS_Printf(M_GetText("File %s not found.\n"), fn);
+		else // file not found
 			return;
-		}
 #endif
 		WRITEMEM(buf_p, md5sum, 16);
 	}
diff --git a/src/p_mobj.c b/src/p_mobj.c
index b7cb83881..17d5d13b3 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -7359,6 +7359,18 @@ void P_MobjThinker(mobj_t *mobj)
 		}
 	else switch (mobj->type)
 	{
+		case MT_FALLINGROCK:
+			// Despawn rocks here in case zmovement code can't do so (blame slopes)
+			if (!mobj->momx && !mobj->momy && !mobj->momz
+			&& ((mobj->eflags & MFE_VERTICALFLIP) ?
+				  mobj->z + mobj->height >= mobj->ceilingz
+				: mobj->z <= mobj->floorz))
+			{
+				P_RemoveMobj(mobj);
+				return;
+			}
+			P_MobjCheckWater(mobj);
+			break;
 		case MT_EMERALDSPAWN:
 			if (mobj->threshold)
 			{
diff --git a/src/v_video.c b/src/v_video.c
index fb02dfc96..3f2ab31f8 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -773,79 +773,80 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
 {
 	UINT8 *dest;
 	const UINT8 *deststop;
-	INT32 u, v, dupx, dupy;
+
+	if (rendermode == render_none)
+		return;
 
 #ifdef HWRENDER
-	if (rendermode != render_soft && rendermode != render_none)
+	if (rendermode != render_soft && !con_startup)
 	{
 		HWR_DrawFill(x, y, w, h, c);
 		return;
 	}
 #endif
 
-	dupx = vid.dupx;
-	dupy = vid.dupy;
-
-	if (!screens[0])
-		return;
-
-	if (c & V_NOSCALESTART)
-	{
-		dest = screens[0] + y*vid.width + x;
-		deststop = screens[0] + vid.rowbytes * vid.height;
-	}
-	else
+	if (!(c & V_NOSCALESTART))
 	{
+		INT32 dupx = vid.dupx, dupy = vid.dupy;
+
 		if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
 		{ // Clear the entire screen, from dest to deststop. Yes, this really works.
 			memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
 			return;
 		}
 
-		dest = screens[0] + y*dupy*vid.width + x*dupx;
-		deststop = screens[0] + vid.rowbytes * vid.height;
+		x *= dupx;
+		y *= dupy;
+		w *= dupx;
+		h *= dupy;
 
-		if (w == BASEVIDWIDTH)
-			w = vid.width;
-		else
-			w *= dupx;
-		if (h == BASEVIDHEIGHT)
-			h = vid.height;
-		else
-			h *= dupy;
-
-		if (x && y && x + w < vid.width && y + h < vid.height)
+		// Center it if necessary
+		if (vid.width != BASEVIDWIDTH * dupx)
 		{
-			// Center it if necessary
-			if (vid.width != BASEVIDWIDTH * dupx)
-			{
-				// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
-				// so center this imaginary screen
-				if (c & V_SNAPTORIGHT)
-					dest += (vid.width - (BASEVIDWIDTH * dupx));
-				else if (!(c & V_SNAPTOLEFT))
-					dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
-			}
-			if (vid.height != BASEVIDHEIGHT * dupy)
-			{
-				// same thing here
-				if (c & V_SNAPTOBOTTOM)
-					dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width;
-				else if (!(c & V_SNAPTOTOP))
-					dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2;
-			}
+			// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
+			// so center this imaginary screen
+			if (c & V_SNAPTORIGHT)
+				x += (vid.width - (BASEVIDWIDTH * dupx));
+			else if (!(c & V_SNAPTOLEFT))
+				x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
+		}
+		if (vid.height != BASEVIDHEIGHT * dupy)
+		{
+			// same thing here
+			if (c & V_SNAPTOBOTTOM)
+				y += (vid.height - (BASEVIDHEIGHT * dupy));
+			else if (!(c & V_SNAPTOTOP))
+				y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
 		}
 	}
 
+	if (x >= vid.width || y >= vid.height)
+		return; // off the screen
+	if (x < 0)
+	{
+		w += x;
+		x = 0;
+	}
+	if (y < 0)
+	{
+		h += y;
+		y = 0;
+	}
+
+	if (w <= 0 || h <= 0)
+		return; // zero width/height wouldn't draw anything
+	if (x + w > vid.width)
+		w = vid.width - x;
+	if (y + h > vid.height)
+		h = vid.height - y;
+
+	dest = screens[0] + y*vid.width + x;
+	deststop = screens[0] + vid.rowbytes * vid.height;
+
 	c &= 255;
 
-	for (v = 0; v < h; v++, dest += vid.width)
-		for (u = 0; u < w; u++)
-		{
-			if (dest > deststop)
-				return;
-			dest[u] = (UINT8)c;
-		}
+	for (;(--h >= 0) && dest < deststop; dest += vid.width)
+		memset(dest, (UINT8)(c&255), w * vid.bpp);
 }
 
 //
diff --git a/src/w_wad.c b/src/w_wad.c
index ecba4064f..b1b72eec1 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -133,6 +133,47 @@ void W_Shutdown(void)
 
 static char filenamebuf[MAX_WADPATH];
 
+// W_OpenWadFile
+// Helper function for opening the WAD file.
+// Returns the FILE * handle for the file, or NULL if not found or could not be opened
+// If "useerrors" is true then print errors in the console, else just don't bother
+// "filename" may be modified to have the correct path the actual file is located in, if necessary
+FILE *W_OpenWadFile(const char **filename, boolean useerrors)
+{
+	FILE *handle;
+
+	strncpy(filenamebuf, *filename, MAX_WADPATH);
+	filenamebuf[MAX_WADPATH - 1] = '\0';
+	*filename = filenamebuf;
+
+	// open wad file
+	if ((handle = fopen(*filename, "rb")) == NULL)
+	{
+		// If we failed to load the file with the path as specified by
+		// the user, strip the directories and search for the file.
+		nameonly(filenamebuf);
+
+		// If findfile finds the file, the full path will be returned
+		// in filenamebuf == *filename.
+		if (findfile(filenamebuf, NULL, true))
+		{
+			if ((handle = fopen(*filename, "rb")) == NULL)
+			{
+				if (useerrors)
+					CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), *filename);
+				return NULL;
+			}
+		}
+		else
+		{
+			if (useerrors)
+				CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), *filename);
+			return NULL;
+		}
+	}
+	return handle;
+}
+
 // search for all DEHACKED lump in all wads and load it
 static inline void W_LoadDehackedLumps(UINT16 wadnum)
 {
@@ -234,7 +275,6 @@ static void W_InvalidateLumpnumCache(void)
 	memset(lumpnumcache, 0, sizeof (lumpnumcache));
 }
 
-
 //  Allocate a wadfile, setup the lumpinfo (directory) and
 //  lumpcache, add the wadfile to the current active wadfiles
 //
@@ -271,33 +311,9 @@ UINT16 W_LoadWadFile(const char *filename)
 		return INT16_MAX;
 	}
 
-	strncpy(filenamebuf, filename, MAX_WADPATH);
-	filenamebuf[MAX_WADPATH - 1] = '\0';
-	filename = filenamebuf;
-
 	// open wad file
-	if ((handle = fopen(filename, "rb")) == NULL)
-	{
-		// If we failed to load the file with the path as specified by
-		// the user, strip the directories and search for the file.
-		nameonly(filenamebuf);
-
-		// If findfile finds the file, the full path will be returned
-		// in filenamebuf == filename.
-		if (findfile(filenamebuf, NULL, true))
-		{
-			if ((handle = fopen(filename, "rb")) == NULL)
-			{
-				CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), filename);
-				return INT16_MAX;
-			}
-		}
-		else
-		{
-			CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), filename);
-			return INT16_MAX;
-		}
-	}
+	if ((handle = W_OpenWadFile(&filename, true)) == NULL)
+		return INT16_MAX;
 
 	// Check if wad files will overflow fileneededbuffer. Only the filename part
 	// is send in the packet; cf.
@@ -1115,21 +1131,11 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
 	size_t i, j;
 	int goodfile = false;
 
-	if (!checklist) I_Error("No checklist for %s\n", filename);
-	strlcpy(filenamebuf, filename, MAX_WADPATH);
-	filename = filenamebuf;
+	if (!checklist)
+		I_Error("No checklist for %s\n", filename);
 	// open wad file
-	if ((handle = fopen(filename, "rb")) == NULL)
-	{
-		nameonly(filenamebuf); // leave full path here
-		if (findfile(filenamebuf, NULL, true))
-		{
-			if ((handle = fopen(filename, "rb")) == NULL)
-				return -1;
-		}
-		else
-			return -1;
-	}
+	if ((handle = W_OpenWadFile(&filename, false)) == NULL)
+		return -1;
 
 	// detect dehacked file with the "soc" extension
 	if (stricmp(&filename[strlen(filename) - 4], ".soc") != 0
diff --git a/src/w_wad.h b/src/w_wad.h
index b03e376bf..f7ea64a56 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -82,6 +82,8 @@ extern wadfile_t *wadfiles[MAX_WADFILES];
 
 void W_Shutdown(void);
 
+// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened
+FILE *W_OpenWadFile(const char **filename, boolean useerrors);
 // Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
 UINT16 W_LoadWadFile(const char *filename);
 #ifdef DELFILE