diff --git a/src/actor.h b/src/actor.h
index 60a00582f9..28e68b64a6 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -283,7 +283,7 @@ enum ActorFlag4
 enum ActorFlag5
 {
 	MF5_DONTDRAIN		= 0x00000001,	// cannot be drained health from.
-	/*		FREE SLOT	  0x00000002*/
+	MF5_GETOWNER		= 0x00000002,
 	MF5_NODROPOFF		= 0x00000004,	// cannot drop off under any circumstances.
 	MF5_NOFORWARDFALL	= 0x00000008,	// Does not make any actor fall forward by being damaged by this
 	MF5_COUNTSECRET		= 0x00000010,	// From Doom 64: actor acts like a secret
diff --git a/src/c_console.cpp b/src/c_console.cpp
index 850a29455d..08f850675f 100644
--- a/src/c_console.cpp
+++ b/src/c_console.cpp
@@ -159,12 +159,37 @@ static int HistSize;
 
 CVAR (Float, con_notifytime, 3.f, CVAR_ARCHIVE)
 CVAR (Bool, con_centernotify, false, CVAR_ARCHIVE)
-CUSTOM_CVAR (Int, con_scaletext, 0, CVAR_ARCHIVE)		// Scale notify text at high resolutions?
+CUSTOM_CVAR (Int, con_scaletext, 1, CVAR_ARCHIVE)		// Scale notify text at high resolutions?
 {
 	if (self < 0) self = 0;
 	if (self > 3) self = 3;
 }
 
+CUSTOM_CVAR(Int, con_scale, 0, CVAR_ARCHIVE)
+{
+	if (self < 0) self = 0;
+}
+
+int active_con_scale()
+{
+	if (con_scale == 0)
+		return uiscale;
+	else
+		return con_scale;
+}
+
+int active_con_scaletext()
+{
+	switch (con_scaletext)
+	{
+	default:
+	case 0: return 1;
+	case 1: return uiscale;
+	case 2: return 2;
+	case 3: return 4;
+	}
+}
+
 CUSTOM_CVAR(Float, con_alpha, 0.75f, CVAR_ARCHIVE)
 {
 	if (self < 0.f) self = 0.f;
@@ -493,13 +518,13 @@ void C_AddNotifyString (int printlevel, const char *source)
 		return;
 	}
 
-	switch (con_scaletext)
+	if (active_con_scaletext() == 0)
 	{
-	default:
-	case 0: width = DisplayWidth; break;
-	case 1: width = DisplayWidth / CleanXfac; break;
-	case 2: width = DisplayWidth / 2; break;
-	case 3: width = DisplayWidth / 4; break;
+		width = DisplayWidth / CleanXfac;
+	}
+	else
+	{
+		width = DisplayWidth / active_con_scaletext();
 	}
 
 	if (addtype == APPENDLINE && NotifyStrings[NUMNOTIFIES-1].PrintLevel == printlevel)
@@ -721,7 +746,7 @@ static void C_DrawNotifyText ()
 	canskip = true;
 
 	lineadv = SmallFont->GetHeight ();
-	if (con_scaletext == 1)
+	if (active_con_scaletext() == 0)
 	{
 		lineadv *= CleanYfac;
 	}
@@ -755,7 +780,7 @@ static void C_DrawNotifyText ()
 			else
 				color = PrintColors[NotifyStrings[i].PrintLevel];
 
-			if (con_scaletext == 1)
+			if (active_con_scaletext() == 0)
 			{
 				if (!center)
 					screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text,
@@ -766,7 +791,7 @@ static void C_DrawNotifyText ()
 						line, NotifyStrings[i].Text, DTA_CleanNoMove, true,
 						DTA_AlphaF, alpha, TAG_DONE);
 			}
-			else if (con_scaletext == 0)
+			else if (active_con_scaletext() == 1)
 			{
 				if (!center)
 					screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text,
@@ -777,37 +802,20 @@ static void C_DrawNotifyText ()
 						line, NotifyStrings[i].Text,
 						DTA_AlphaF, alpha, TAG_DONE);
 			}
-			else if (con_scaletext == 3)
-			{
-				if (!center)
-					screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text,
-						DTA_VirtualWidth, screen->GetWidth() / 4, 
-						DTA_VirtualHeight, screen->GetHeight() / 4,
-						DTA_KeepRatio, true,
-						DTA_AlphaF, alpha, TAG_DONE);
-				else
-					screen->DrawText (SmallFont, color, (screen->GetWidth() / 4 -
-						SmallFont->StringWidth (NotifyStrings[i].Text))/4,
-						line, NotifyStrings[i].Text,
-						DTA_VirtualWidth, screen->GetWidth() / 4, 
-						DTA_VirtualHeight, screen->GetHeight() / 4,
-						DTA_KeepRatio, true,
-						DTA_AlphaF, alpha, TAG_DONE);
-			}
 			else
 			{
 				if (!center)
 					screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text,
-						DTA_VirtualWidth, screen->GetWidth() / 2, 
-						DTA_VirtualHeight, screen->GetHeight() / 2,
+						DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(),
+						DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(),
 						DTA_KeepRatio, true,
 						DTA_AlphaF, alpha, TAG_DONE);
 				else
-					screen->DrawText (SmallFont, color, (screen->GetWidth() / 2 -
-						SmallFont->StringWidth (NotifyStrings[i].Text))/2,
+					screen->DrawText (SmallFont, color, (screen->GetWidth() / active_con_scaletext() -
+						SmallFont->StringWidth (NotifyStrings[i].Text))/ active_con_scaletext(),
 						line, NotifyStrings[i].Text,
-						DTA_VirtualWidth, screen->GetWidth() / 2, 
-						DTA_VirtualHeight, screen->GetHeight() / 2,
+						DTA_VirtualWidth, screen->GetWidth() / active_con_scaletext(),
+						DTA_VirtualHeight, screen->GetHeight() / active_con_scaletext(),
 						DTA_KeepRatio, true,
 						DTA_AlphaF, alpha, TAG_DONE);
 			}
@@ -851,9 +859,13 @@ void C_DrawConsole (bool hw2d)
 	static int oldbottom = 0;
 	int lines, left, offset;
 
+	int textScale = active_con_scale();
+	if (textScale == 0)
+		textScale = CleanXfac;
+
 	left = LEFTMARGIN;
-	lines = (ConBottom-ConFont->GetHeight()*2)/ConFont->GetHeight();
-	if (-ConFont->GetHeight() + lines*ConFont->GetHeight() > ConBottom - ConFont->GetHeight()*7/2)
+	lines = (ConBottom/textScale-ConFont->GetHeight()*2)/ConFont->GetHeight();
+	if (-ConFont->GetHeight() + lines*ConFont->GetHeight() > ConBottom/textScale - ConFont->GetHeight()*7/2)
 	{
 		offset = -ConFont->GetHeight()/2;
 		lines--;
@@ -899,16 +911,26 @@ void C_DrawConsole (bool hw2d)
 
 		if (ConBottom >= 12)
 		{
-			screen->DrawText (ConFont, CR_ORANGE, SCREENWIDTH - 8 -
-				ConFont->StringWidth (GetVersionString()),
-				ConBottom - ConFont->GetHeight() - 4,
-				GetVersionString(), TAG_DONE);
+			if (textScale == 1)
+				screen->DrawText (ConFont, CR_ORANGE, SCREENWIDTH - 8 -
+					ConFont->StringWidth (GetVersionString()),
+					ConBottom / textScale - ConFont->GetHeight() - 4,
+					GetVersionString(), TAG_DONE);
+			else
+				screen->DrawText(ConFont, CR_ORANGE, SCREENWIDTH / textScale - 8 -
+					ConFont->StringWidth(GetVersionString()),
+					ConBottom / textScale - ConFont->GetHeight() - 4,
+					GetVersionString(),
+					DTA_VirtualWidth, screen->GetWidth() / textScale,
+					DTA_VirtualHeight, screen->GetHeight() / textScale,
+					DTA_KeepRatio, true, TAG_DONE);
+
 			if (TickerMax)
 			{
 				char tickstr[256];
-				const int tickerY = ConBottom - ConFont->GetHeight() - 4;
+				const int tickerY = ConBottom / textScale - ConFont->GetHeight() - 4;
 				size_t i;
-				int tickend = ConCols - SCREENWIDTH / 90 - 6;
+				int tickend = ConCols / textScale - SCREENWIDTH / textScale / 90 - 6;
 				int tickbegin = 0;
 
 				if (TickerLabel)
@@ -931,11 +953,23 @@ void C_DrawConsole (bool hw2d)
 				{
 					tickstr[tickend+3] = 0;
 				}
-				screen->DrawText (ConFont, CR_BROWN, LEFTMARGIN, tickerY, tickstr, TAG_DONE);
+				if (textScale == 1)
+					screen->DrawText (ConFont, CR_BROWN, LEFTMARGIN, tickerY, tickstr, TAG_DONE);
+				else
+					screen->DrawText (ConFont, CR_BROWN, LEFTMARGIN, tickerY, tickstr,
+						DTA_VirtualWidth, screen->GetWidth() / textScale,
+						DTA_VirtualHeight, screen->GetHeight() / textScale,
+						DTA_KeepRatio, true, TAG_DONE);
 
 				// Draw the marker
 				i = LEFTMARGIN+5+tickbegin*8 + Scale (TickerAt, (SDWORD)(tickend - tickbegin)*8, TickerMax);
-				screen->DrawChar (ConFont, CR_ORANGE, (int)i, tickerY, 0x13, TAG_DONE);
+				if (textScale == 1)
+					screen->DrawChar (ConFont, CR_ORANGE, (int)i, tickerY, 0x13, TAG_DONE);
+				else
+					screen->DrawChar(ConFont, CR_ORANGE, (int)i, tickerY, 0x13,
+						DTA_VirtualWidth, screen->GetWidth() / textScale,
+						DTA_VirtualHeight, screen->GetHeight() / textScale,
+						DTA_KeepRatio, true, TAG_DONE);
 
 				TickerVisible = true;
 			}
@@ -971,18 +1005,28 @@ void C_DrawConsole (bool hw2d)
 	if (lines > 0)
 	{
 		// No more enqueuing because adding new text to the console won't touch the actual print data.
-		conbuffer->FormatText(ConFont, ConWidth);
+		conbuffer->FormatText(ConFont, ConWidth / textScale);
 		unsigned int consolelines = conbuffer->GetFormattedLineCount();
 		FBrokenLines **blines = conbuffer->GetLines();
 		FBrokenLines **printline = blines + consolelines - 1 - RowAdjust;
 
-		int bottomline = ConBottom - ConFont->GetHeight()*2 - 4;
+		int bottomline = ConBottom / textScale - ConFont->GetHeight()*2 - 4;
 
 		ConsoleDrawing = true;
 
 		for(FBrokenLines **p = printline; p >= blines && lines > 0; p--, lines--)
 		{
-			screen->DrawText(ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), (*p)->Text, TAG_DONE);
+			if (textScale == 1)
+			{
+				screen->DrawText(ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), (*p)->Text, TAG_DONE);
+			}
+			else
+			{
+				screen->DrawText(ConFont, CR_TAN, LEFTMARGIN, offset + lines * ConFont->GetHeight(), (*p)->Text,
+					DTA_VirtualWidth, screen->GetWidth() / textScale,
+					DTA_VirtualHeight, screen->GetHeight() / textScale,
+					DTA_KeepRatio, true, TAG_DONE);
+			}
 		}
 
 		ConsoleDrawing = false;
@@ -997,21 +1041,52 @@ void C_DrawConsole (bool hw2d)
 				FString command((char *)&CmdLine[2+CmdLine[259]]);
 				int cursorpos = CmdLine[1] - CmdLine[259];
 
-				screen->DrawChar (ConFont, CR_ORANGE, left, bottomline, '\x1c', TAG_DONE);
-				screen->DrawText (ConFont, CR_ORANGE, left + ConFont->GetCharWidth(0x1c), bottomline,
-					command, TAG_DONE);
-
-				if (cursoron)
+				if (textScale == 1)
 				{
-					screen->DrawChar (ConFont, CR_YELLOW, left + ConFont->GetCharWidth(0x1c) + cursorpos * ConFont->GetCharWidth(0xb),
-						bottomline, '\xb', TAG_DONE);
+					screen->DrawChar(ConFont, CR_ORANGE, left, bottomline, '\x1c', TAG_DONE);
+					screen->DrawText(ConFont, CR_ORANGE, left + ConFont->GetCharWidth(0x1c), bottomline,
+						command, TAG_DONE);
+
+					if (cursoron)
+					{
+						screen->DrawChar(ConFont, CR_YELLOW, left + ConFont->GetCharWidth(0x1c) + cursorpos * ConFont->GetCharWidth(0xb),
+							bottomline, '\xb', TAG_DONE);
+					}
+				}
+				else
+				{
+					screen->DrawChar(ConFont, CR_ORANGE, left, bottomline, '\x1c',
+						DTA_VirtualWidth, screen->GetWidth() / textScale,
+						DTA_VirtualHeight, screen->GetHeight() / textScale,
+						DTA_KeepRatio, true, TAG_DONE);
+
+					screen->DrawText(ConFont, CR_ORANGE, left + ConFont->GetCharWidth(0x1c), bottomline,
+						command,
+						DTA_VirtualWidth, screen->GetWidth() / textScale,
+						DTA_VirtualHeight, screen->GetHeight() / textScale,
+						DTA_KeepRatio, true, TAG_DONE);
+
+					if (cursoron)
+					{
+						screen->DrawChar(ConFont, CR_YELLOW, left + ConFont->GetCharWidth(0x1c) + cursorpos * ConFont->GetCharWidth(0xb),
+							bottomline, '\xb',
+							DTA_VirtualWidth, screen->GetWidth() / textScale,
+							DTA_VirtualHeight, screen->GetHeight() / textScale,
+							DTA_KeepRatio, true, TAG_DONE);
+					}
 				}
 			}
 			if (RowAdjust && ConBottom >= ConFont->GetHeight()*7/2)
 			{
 				// Indicate that the view has been scrolled up (10)
 				// and if we can scroll no further (12)
-				screen->DrawChar (ConFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, TAG_DONE);
+				if (textScale == 1)
+					screen->DrawChar (ConFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10, TAG_DONE);
+				else
+					screen->DrawChar(ConFont, CR_GREEN, 0, bottomline, RowAdjust == conbuffer->GetFormattedLineCount() ? 12 : 10,
+						DTA_VirtualWidth, screen->GetWidth() / textScale,
+						DTA_VirtualHeight, screen->GetHeight() / textScale,
+						DTA_KeepRatio, true, TAG_DONE);
 			}
 		}
 	}
diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp
index b053d8bd86..3c0994a3b4 100644
--- a/src/ct_chat.cpp
+++ b/src/ct_chat.cpp
@@ -46,6 +46,8 @@ EXTERN_CVAR (Bool, sb_cooperative_enable)
 EXTERN_CVAR (Bool, sb_deathmatch_enable)
 EXTERN_CVAR (Bool, sb_teamdeathmatch_enable)
 
+int active_con_scaletext();
+
 // Public data
 
 void CT_Init ();
@@ -224,7 +226,7 @@ void CT_Drawer (void)
 		int i, x, scalex, y, promptwidth;
 
 		y = (viewactive || gamestate != GS_LEVEL) ? -10 : -30;
-		if (con_scaletext == 1)
+		if (active_con_scaletext() == 0)
 		{
 			scalex = CleanXfac;
 			y *= CleanYfac;
@@ -235,25 +237,17 @@ void CT_Drawer (void)
 		}
 
 		int screen_width, screen_height, st_y;
-		switch (con_scaletext)
+		if (active_con_scaletext() == 0)
 		{
-		default:
-		case 0:
-		case 1:
 			screen_width = SCREENWIDTH;
 			screen_height = SCREENHEIGHT;
 			st_y = ST_Y;
-			break;
-		case 2:
-			screen_width = SCREENWIDTH / 2;
-			screen_height = SCREENHEIGHT / 2;
-			st_y = ST_Y / 2;
-			break;
-		case 3:
-			screen_width = SCREENWIDTH / 4;
-			screen_height = SCREENHEIGHT / 4;
-			st_y = ST_Y / 4;
-			break;
+		}
+		else
+		{
+			screen_width = SCREENWIDTH / active_con_scaletext();
+			screen_height = SCREENHEIGHT / active_con_scaletext();
+			st_y = ST_Y / active_con_scaletext();
 		}
 
 		y += ((SCREENHEIGHT == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y;
@@ -280,10 +274,10 @@ void CT_Drawer (void)
 		// draw the prompt, text, and cursor
 		ChatQueue[len] = SmallFont->GetCursor();
 		ChatQueue[len+1] = '\0';
-		if (con_scaletext < 2)
+		if (active_con_scaletext() < 2)
 		{
-			screen->DrawText (SmallFont, CR_GREEN, 0, y, prompt, DTA_CleanNoMove, *con_scaletext, TAG_DONE);
-			screen->DrawText (SmallFont, CR_GREY, promptwidth, y, (char *)(ChatQueue + i), DTA_CleanNoMove, *con_scaletext, TAG_DONE);
+			screen->DrawText (SmallFont, CR_GREEN, 0, y, prompt, DTA_CleanNoMove, active_con_scaletext() == 0, TAG_DONE);
+			screen->DrawText (SmallFont, CR_GREY, promptwidth, y, (char *)(ChatQueue + i), DTA_CleanNoMove, active_con_scaletext() == 0, TAG_DONE);
 		}
 		else
 		{
diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp
index 8c7d63b742..c1253f9662 100644
--- a/src/g_shared/a_fastprojectile.cpp
+++ b/src/g_shared/a_fastprojectile.cpp
@@ -166,8 +166,14 @@ void AFastProjectile::Effect()
 		if (trail != NULL)
 		{
 			AActor *act = Spawn (trail, PosAtZ(hitz), ALLOW_REPLACE);
-			if (act != NULL)
+			if (act != nullptr)
 			{
+				if ((flags5 & MF5_GETOWNER) && (target != nullptr))
+					act->target = target;
+				else
+					act->target = this;
+				
+				act->Angles.Pitch = Angles.Pitch;
 				act->Angles.Yaw = Angles.Yaw;
 			}
 		}
diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp
index 74c416468b..aae006ca79 100644
--- a/src/g_shared/a_quake.cpp
+++ b/src/g_shared/a_quake.cpp
@@ -161,7 +161,7 @@ double DEarthquake::GetModWave(double waveMultiplier) const
 //
 //==========================================================================
 
-double DEarthquake::GetModIntensity(double intensity) const
+double DEarthquake::GetModIntensity(double intensity, bool fake) const
 {
 	assert(m_CountdownStart >= m_Countdown);
 
@@ -195,7 +195,7 @@ double DEarthquake::GetModIntensity(double intensity) const
 			}
 			scalar = (scalar > divider) ? divider : scalar;
 
-			if (m_Flags & QF_FULLINTENSITY)
+			if (!fake && (m_Flags & QF_FULLINTENSITY))
 			{
 				scalar *= 2;
 			}
@@ -273,64 +273,69 @@ int DEarthquake::StaticGetQuakeIntensities(AActor *victim, FQuakeJiggers &jigger
 	DEarthquake *quake;
 	int count = 0;
 
-	while ( (quake = iterator.Next()) != NULL)
+	while ( (quake = iterator.Next()) != nullptr)
 	{
-		if (quake->m_Spot != NULL)
+		if (quake->m_Spot != nullptr)
 		{
-			double dist = quake->m_Spot->Distance2D (victim, true);
+			const double dist = quake->m_Spot->Distance2D(victim, true);
 			if (dist < quake->m_TremorRadius)
 			{
-				const double falloff = quake->GetFalloff(dist);
-				const double rfalloff = (quake->m_RollIntensity != 0) ? falloff : 0.;
 				++count;
-				double x = quake->GetModIntensity(quake->m_Intensity.X);
-				double y = quake->GetModIntensity(quake->m_Intensity.Y);
-				double z = quake->GetModIntensity(quake->m_Intensity.Z);
-				double r = quake->GetModIntensity(quake->m_RollIntensity);
+				const double falloff = quake->GetFalloff(dist);
+				const double r = quake->GetModIntensity(quake->m_RollIntensity);
+				const double strength = quake->GetModIntensity(1.0, true);
+				DVector3 intensity;
+				intensity.X = quake->GetModIntensity(quake->m_Intensity.X);
+				intensity.Y = quake->GetModIntensity(quake->m_Intensity.Y);
+				intensity.Z = quake->GetModIntensity(quake->m_Intensity.Z);
 
 				if (!(quake->m_Flags & QF_WAVE))
 				{
 					jiggers.Falloff = MAX(falloff, jiggers.Falloff);
-					jiggers.RFalloff = MAX(rfalloff, jiggers.RFalloff);
-					jiggers.RollIntensity = MAX(r, jiggers.RollIntensity);
+					jiggers.RollIntensity = MAX(r, jiggers.RollIntensity) * jiggers.Falloff;
+
+					intensity *= jiggers.Falloff;
 					if (quake->m_Flags & QF_RELATIVE)
 					{
-						jiggers.RelIntensity.X = MAX(x, jiggers.RelIntensity.X);
-						jiggers.RelIntensity.Y = MAX(y, jiggers.RelIntensity.Y);
-						jiggers.RelIntensity.Z = MAX(z, jiggers.RelIntensity.Z);
+						jiggers.RelIntensity.X = MAX(intensity.X, jiggers.RelIntensity.X);
+						jiggers.RelIntensity.Y = MAX(intensity.Y, jiggers.RelIntensity.Y);
+						jiggers.RelIntensity.Z = MAX(intensity.Z, jiggers.RelIntensity.Z);
 					}
 					else
 					{
-						jiggers.Intensity.X = MAX(x, jiggers.Intensity.X);
-						jiggers.Intensity.Y = MAX(y, jiggers.Intensity.Y);
-						jiggers.Intensity.Z = MAX(z, jiggers.Intensity.Z);
+						jiggers.Intensity.X = MAX(intensity.X, jiggers.Intensity.X);
+						jiggers.Intensity.Y = MAX(intensity.Y, jiggers.Intensity.Y);
+						jiggers.Intensity.Z = MAX(intensity.Z, jiggers.Intensity.Z);
 					}
 				}
 				else
 				{
-					jiggers.WFalloff = MAX(falloff, jiggers.WFalloff);
-					jiggers.RWFalloff = MAX(rfalloff, jiggers.RWFalloff);
-					jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave);
-					double mx = x * quake->GetModWave(quake->m_WaveSpeed.X);
-					double my = y * quake->GetModWave(quake->m_WaveSpeed.Y);
-					double mz = z * quake->GetModWave(quake->m_WaveSpeed.Z);
+					jiggers.Falloff = MAX(falloff, jiggers.Falloff);
+					jiggers.RollWave = r * quake->GetModWave(quake->m_RollWave) * jiggers.Falloff * strength;
+
+					
+					intensity.X *= quake->GetModWave(quake->m_WaveSpeed.X);
+					intensity.Y *= quake->GetModWave(quake->m_WaveSpeed.Y);
+					intensity.Z *= quake->GetModWave(quake->m_WaveSpeed.Z);
+					intensity *= strength * jiggers.Falloff;
 
 					// [RH] This only gives effect to the last sine quake. I would
 					// prefer if some way was found to make multiples coexist
 					// peacefully, but just summing them together is undesirable
 					// because they could cancel each other out depending on their
 					// relative phases.
+
+					// [MC] Now does so. And they stack rather well. I'm a little
+					// surprised at how easy it was.
+
+					
 					if (quake->m_Flags & QF_RELATIVE)
 					{
-						jiggers.RelOffset.X = mx;
-						jiggers.RelOffset.Y = my;
-						jiggers.RelOffset.Z = mz;
+						jiggers.RelOffset += intensity;
 					}
 					else
 					{
-						jiggers.Offset.X = mx;
-						jiggers.Offset.Y = my;
-						jiggers.Offset.Z = mz;
+						jiggers.Offset += intensity;
 					}
 				}
 			}
diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h
index f873ab0b7d..314061f047 100644
--- a/src/g_shared/a_sharedglobal.h
+++ b/src/g_shared/a_sharedglobal.h
@@ -153,7 +153,7 @@ struct FQuakeJiggers
 	DVector3 RelIntensity;
 	DVector3 Offset;
 	DVector3 RelOffset;
-	double Falloff, WFalloff, RFalloff, RWFalloff;
+	double Falloff;
 	double RollIntensity, RollWave;
 };
 
@@ -180,8 +180,7 @@ public:
 	int m_Highpoint, m_MiniCount;
 	double m_RollIntensity, m_RollWave;
 
-
-	double GetModIntensity(double intensity) const;
+	double GetModIntensity(double intensity, bool fake = false) const;
 	double GetModWave(double waveMultiplier) const;
 	double GetFalloff(double dist) const;
 
diff --git a/src/g_shared/hudmessages.cpp b/src/g_shared/hudmessages.cpp
index 9f13d3d9ef..32a8d2de52 100644
--- a/src/g_shared/hudmessages.cpp
+++ b/src/g_shared/hudmessages.cpp
@@ -41,7 +41,8 @@
 #include "doomstat.h"
 #include "farchive.h"
 
-EXTERN_CVAR (Int, con_scaletext)
+EXTERN_CVAR(Int, con_scaletext)
+int active_con_scaletext();
 
 IMPLEMENT_POINTY_CLASS (DHUDMessage)
  DECLARE_POINTER(Next)
@@ -260,13 +261,10 @@ void DHUDMessage::ResetText (const char *text)
 	}
 	else
 	{
-		switch (con_scaletext)
+		switch (active_con_scaletext())
 		{
-		default:
-		case 0: width = SCREENWIDTH; break;
-		case 1: width = SCREENWIDTH / CleanXfac; break;
-		case 2: width = SCREENWIDTH / 2; break;
-		case 3: width = SCREENWIDTH / 4; break;
+		case 0: width = SCREENWIDTH / CleanXfac; break;
+		default: width = SCREENWIDTH / active_con_scaletext(); break;
 		}
 	}
 
@@ -332,7 +330,7 @@ void DHUDMessage::Draw (int bottom, int visibility)
 
 	int screen_width = SCREENWIDTH;
 	int screen_height = SCREENHEIGHT;
-	if (HUDWidth == 0 && con_scaletext==1)
+	if (HUDWidth == 0 && active_con_scaletext() == 0)
 	{
 		clean = true;
 		xscale = CleanXfac;
@@ -341,17 +339,11 @@ void DHUDMessage::Draw (int bottom, int visibility)
 	else
 	{
 		xscale = yscale = 1;
-		if (HUDWidth==0 && con_scaletext==2) 
+		if (HUDWidth == 0)
 		{
-			screen_width/=2;
-			screen_height/=2;
-			bottom/=2;
-		}
-		else if (HUDWidth==0 && con_scaletext==3)
-		{
-			screen_width/=4;
-			screen_height/=4;
-			bottom/=4;
+			screen_width /= active_con_scaletext();
+			screen_height /= active_con_scaletext();
+			bottom /= active_con_scaletext();
 		}
 	}
 
@@ -453,7 +445,7 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
 {
 	if (hudheight == 0)
 	{
-		if (con_scaletext <= 1)
+		if (active_con_scaletext() <= 1)
 		{
 			screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
 				DTA_CleanNoMove, clean,
@@ -461,21 +453,11 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
 				DTA_RenderStyle, Style,
 				TAG_DONE);
 		}
-		else if (con_scaletext == 3)
-		{
-			screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
-				DTA_VirtualWidth, SCREENWIDTH/4,
-				DTA_VirtualHeight, SCREENHEIGHT/4,
-				DTA_AlphaF, Alpha,
-				DTA_RenderStyle, Style,
-				DTA_KeepRatio, true,
-				TAG_DONE);
-		}
 		else
 		{
 			screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
-				DTA_VirtualWidth, SCREENWIDTH/2,
-				DTA_VirtualHeight, SCREENHEIGHT/2,
+				DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(),
+				DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(),
 				DTA_AlphaF, Alpha,
 				DTA_RenderStyle, Style,
 				DTA_KeepRatio, true,
@@ -566,7 +548,7 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
 		float trans = float(Alpha * -(Tics - FadeOutTics) / FadeOutTics);
 		if (hudheight == 0)
 		{
-			if (con_scaletext <= 1)
+			if (active_con_scaletext() <= 1)
 			{
 				screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
 					DTA_CleanNoMove, clean,
@@ -574,21 +556,11 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
 					DTA_RenderStyle, Style,
 					TAG_DONE);
 			}
-			else if (con_scaletext == 3)
-			{
-				screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
-					DTA_VirtualWidth, SCREENWIDTH/4,
-					DTA_VirtualHeight, SCREENHEIGHT/4,
-					DTA_AlphaF, trans,
-					DTA_RenderStyle, Style,
-					DTA_KeepRatio, true,
-					TAG_DONE);
-			}
 			else
 			{
 				screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
-					DTA_VirtualWidth, SCREENWIDTH/2,
-					DTA_VirtualHeight, SCREENHEIGHT/2,
+					DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(),
+					DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(),
 					DTA_AlphaF, trans,
 					DTA_RenderStyle, Style,
 					DTA_KeepRatio, true,
@@ -676,7 +648,7 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
 		float trans = float(Alpha * Tics / FadeInTics);
 		if (hudheight == 0)
 		{
-			if (con_scaletext <= 1)
+			if (active_con_scaletext() <= 1)
 			{
 				screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
 					DTA_CleanNoMove, clean,
@@ -684,21 +656,11 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
 					DTA_RenderStyle, Style,
 					TAG_DONE);
 			}
-			else if (con_scaletext == 3)
-			{
-				screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
-					DTA_VirtualWidth, SCREENWIDTH/4,
-					DTA_VirtualHeight, SCREENHEIGHT/4,
-					DTA_AlphaF, trans,
-					DTA_RenderStyle, Style,
-					DTA_KeepRatio, true,
-					TAG_DONE);
-			}
 			else
 			{
 				screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
-					DTA_VirtualWidth, SCREENWIDTH/2,
-					DTA_VirtualHeight, SCREENHEIGHT/2,
+					DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(),
+					DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(),
 					DTA_AlphaF, trans,
 					DTA_RenderStyle, Style,
 					DTA_KeepRatio, true,
@@ -864,7 +826,7 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
 		{
 			if (hudheight == 0)
 			{
-				if (con_scaletext <= 1)
+				if (active_con_scaletext() <= 1)
 				{
 					screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
 						DTA_CleanNoMove, clean,
@@ -873,22 +835,11 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
 						DTA_RenderStyle, Style,
 						TAG_DONE);
 				}
-				else if (con_scaletext == 3)
-				{
-					screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
-						DTA_VirtualWidth, SCREENWIDTH/4,
-						DTA_VirtualHeight, SCREENHEIGHT/4,
-						DTA_KeepRatio, true,
-						DTA_TextLen, LineVisible,
-						DTA_AlphaF, Alpha,
-						DTA_RenderStyle, Style,
-						TAG_DONE);
-				}
 				else
 				{
 					screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
-						DTA_VirtualWidth, SCREENWIDTH/2,
-						DTA_VirtualHeight, SCREENHEIGHT/2,
+						DTA_VirtualWidth, SCREENWIDTH / active_con_scaletext(),
+						DTA_VirtualHeight, SCREENHEIGHT / active_con_scaletext(),
 						DTA_KeepRatio, true,
 						DTA_TextLen, LineVisible,
 						DTA_AlphaF, Alpha,
diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp
index 0136b4f256..42f28173c8 100644
--- a/src/g_shared/sbarinfo.cpp
+++ b/src/g_shared/sbarinfo.cpp
@@ -1013,7 +1013,15 @@ public:
 	void ScreenSizeChanged()
 	{
 		Super::ScreenSizeChanged();
-		V_CalcCleanFacs(script->resW, script->resH, SCREENWIDTH, SCREENHEIGHT, &script->cleanX, &script->cleanY);
+		if (uiscale > 0)
+		{
+			script->cleanX = uiscale;
+			script->cleanY = uiscale;
+		}
+		else
+		{
+			V_CalcCleanFacs(script->resW, script->resH, SCREENWIDTH, SCREENHEIGHT, &script->cleanX, &script->cleanY);
+		}
 	}
 
 	void Draw (EHudState state)
diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp
index cddc86ee46..25a88cb352 100644
--- a/src/g_shared/shared_hud.cpp
+++ b/src/g_shared/shared_hud.cpp
@@ -66,7 +66,7 @@ EXTERN_CVAR (Int, screenblocks)
 EXTERN_CVAR (Bool, am_showtime)
 EXTERN_CVAR (Bool, am_showtotaltime)
 
-CVAR(Int,hud_althudscale, 2, CVAR_ARCHIVE)				// Scale the hud to 640x400?
+CVAR(Int,hud_althudscale, 4, CVAR_ARCHIVE)				// Scale the hud to 640x400?
 CVAR(Bool,hud_althud, false, CVAR_ARCHIVE)				// Enable/Disable the alternate HUD
 
 														// These are intentionally not the same as in the automap!
@@ -118,7 +118,7 @@ static int hudwidth, hudheight;				// current width/height for HUD display
 static int statspace;
 
 DVector2 AM_GetPosition();
-
+int active_con_scaletext();
 
 FTextureID GetHUDIcon(PClassInventory *cls)
 {
@@ -886,22 +886,15 @@ static void DrawCoordinates(player_t * CPlayer)
 	}
 
 	int vwidth, vheight;
-	switch (con_scaletext)
+	if (active_con_scaletext() == 0)
 	{
-	default:
-	case 0:
-		vwidth = SCREENWIDTH;
-		vheight = SCREENHEIGHT;
-		break;
-	case 1:
-	case 2:
-		vwidth = SCREENWIDTH/2;
-		vheight = SCREENHEIGHT/2;
-		break;
-	case 3:
-		vwidth = SCREENWIDTH/4;
-		vheight = SCREENHEIGHT/4;
-		break;
+		vwidth = SCREENWIDTH / 2;
+		vheight = SCREENHEIGHT / 2;
+	}
+	else
+	{
+		vwidth = SCREENWIDTH / active_con_scaletext();
+		vheight = SCREENHEIGHT / active_con_scaletext();
 	}
 
 	int xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
@@ -1090,7 +1083,20 @@ void DrawHUD()
 	if (hud_althudscale && SCREENWIDTH>640) 
 	{
 		hudwidth=SCREENWIDTH/2;
-		if (hud_althudscale == 3)
+		if (hud_althudscale == 4)
+		{
+			if (uiscale == 0)
+			{
+				hudwidth = CleanWidth;
+				hudheight = CleanHeight;
+			}
+			else
+			{
+				hudwidth = SCREENWIDTH / uiscale;
+				hudheight = SCREENHEIGHT / uiscale;
+			}
+		}
+		else if (hud_althudscale == 3)
 		{
 			hudwidth = SCREENWIDTH / 4;
 			hudheight = SCREENHEIGHT / 4;
diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp
index c3b1fd262b..4631a99aa6 100644
--- a/src/g_shared/shared_sbar.cpp
+++ b/src/g_shared/shared_sbar.cpp
@@ -74,6 +74,8 @@ EXTERN_CVAR (Bool, am_showtotaltime)
 EXTERN_CVAR (Bool, noisedebug)
 EXTERN_CVAR (Int, con_scaletext)
 
+int active_con_scaletext();
+
 DBaseStatusBar *StatusBar;
 
 extern int setblocks;
@@ -1240,17 +1242,17 @@ void DBaseStatusBar::Draw (EHudState state)
 		int xpos;
 		int y;
 
-		if (con_scaletext == 0)
+		if (active_con_scaletext() == 1)
 		{
 			vwidth = SCREENWIDTH;
 			vheight = SCREENHEIGHT;
 			xpos = vwidth - 80;
 			y = ::ST_Y - height;
 		}
-		else if (con_scaletext == 3)
+		else if (active_con_scaletext() > 1)
 		{
-			vwidth = SCREENWIDTH/4;
-			vheight = SCREENHEIGHT/4;
+			vwidth = SCREENWIDTH / active_con_scaletext();
+			vheight = SCREENHEIGHT / active_con_scaletext();
 			xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
 			y = ::ST_Y/4 - height;
 		}
@@ -1264,9 +1266,9 @@ void DBaseStatusBar::Draw (EHudState state)
 
 		if (gameinfo.gametype == GAME_Strife)
 		{
-			if (con_scaletext == 0)
+			if (active_con_scaletext() == 1)
 				y -= height * 4;
-			else if (con_scaletext == 3)
+			else if (active_con_scaletext() > 3)
 				y -= height;
 			else
 				y -= height * 2;
@@ -1400,27 +1402,15 @@ void DBaseStatusBar::DrawLog ()
 	if (CPlayer->LogText.IsNotEmpty())
 	{
 		// This uses the same scaling as regular HUD messages
-		switch (con_scaletext)
+		if (active_con_scaletext() == 0)
 		{
-		default:
-			hudwidth = SCREENWIDTH;
-			hudheight = SCREENHEIGHT;
-			break;
-
-		case 1:
 			hudwidth = SCREENWIDTH / CleanXfac;
 			hudheight = SCREENHEIGHT / CleanYfac;
-			break;
-
-		case 2:
-			hudwidth = SCREENWIDTH / 2;
-			hudheight = SCREENHEIGHT / 2;
-			break;
-
-		case 3:
-			hudwidth = SCREENWIDTH / 4;
-			hudheight = SCREENHEIGHT / 4;
-			break;
+		}
+		else
+		{
+			hudwidth = SCREENWIDTH / active_con_scaletext();
+			hudheight = SCREENHEIGHT / active_con_scaletext();
 		}
 
 		int linelen = hudwidth<640? Scale(hudwidth,9,10)-40 : 560;
diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index 0157fda758..67ae377717 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -4451,6 +4451,7 @@ enum EACSFunctions
 
 	ACSF_CheckClass = 200,
 	ACSF_DamageActor, // [arookas]
+	ACSF_SetActorFlag,
 
 	// ZDaemon
 	ACSF_GetTeamScore = 19620,	// (int team)
@@ -6046,6 +6047,34 @@ doplaysound:			if (funcIndex == ACSF_PlayActorSound)
 			return P_DamageMobj(target, inflictor, inflictor, args[4], damagetype);
 		}
 
+		case ACSF_SetActorFlag:
+		{
+			int tid = args[0];
+			FString flagname = FBehavior::StaticLookupString(args[1]);
+			bool flagvalue = !!args[2];
+			int count = 0; // Return value; number of actors affected
+			if (tid == 0)
+			{
+				if (ModActorFlag(activator, flagname, flagvalue))
+				{
+					++count;
+				}
+			}
+			else
+			{
+				FActorIterator it(tid);
+				while ((actor = it.Next()) != nullptr)
+				{
+					// Don't log errors when affecting many actors because things might share a TID but not share the flag
+					if (ModActorFlag(actor, flagname, flagvalue, false))
+					{
+						++count;
+					}
+				}
+			}
+			return count;
+		}
+
 		default:
 			break;
 	}
diff --git a/src/r_utility.cpp b/src/r_utility.cpp
index 71d3f23769..00ac91c971 100644
--- a/src/r_utility.cpp
+++ b/src/r_utility.cpp
@@ -656,7 +656,7 @@ void R_AddInterpolationPoint(const DVector3a &vec)
 //
 //==========================================================================
 
-static double QuakePower(double factor, double intensity, double offset, double falloff, double wfalloff)
+static double QuakePower(double factor, double intensity, double offset)
 { 
 	double randumb;
 	if (intensity == 0)
@@ -667,7 +667,7 @@ static double QuakePower(double factor, double intensity, double offset, double
 	{
 		randumb = pr_torchflicker.GenRand_Real2() * (intensity * 2) - intensity;
 	}
-	return factor * (wfalloff * offset + falloff * randumb);
+	return factor * (offset + randumb);
 }
 
 //==========================================================================
@@ -797,36 +797,36 @@ void R_SetupFrame (AActor *actor)
 
 			if (jiggers.RollIntensity != 0 || jiggers.RollWave != 0)
 			{
-				ViewRoll += QuakePower(quakefactor, jiggers.RollIntensity, jiggers.RollWave, jiggers.RFalloff, jiggers.RWFalloff);
+				ViewRoll += QuakePower(quakefactor, jiggers.RollIntensity, jiggers.RollWave);
 			}
 			if (jiggers.RelIntensity.X != 0 || jiggers.RelOffset.X != 0)
 			{
 				an = camera->Angles.Yaw;
-				double power = QuakePower(quakefactor, jiggers.RelIntensity.X, jiggers.RelOffset.X, jiggers.Falloff, jiggers.WFalloff);
+				double power = QuakePower(quakefactor, jiggers.RelIntensity.X, jiggers.RelOffset.X);
 				ViewPos += an.ToVector(power);
 			}
 			if (jiggers.RelIntensity.Y != 0 || jiggers.RelOffset.Y != 0)
 			{
 				an = camera->Angles.Yaw + 90;
-				double power = QuakePower(quakefactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y, jiggers.Falloff, jiggers.WFalloff);
+				double power = QuakePower(quakefactor, jiggers.RelIntensity.Y, jiggers.RelOffset.Y);
 				ViewPos += an.ToVector(power);
 			}
 			// FIXME: Relative Z is not relative
 			if (jiggers.RelIntensity.Z != 0 || jiggers.RelOffset.Z != 0)
 			{
-				ViewPos.Z += QuakePower(quakefactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z, jiggers.Falloff, jiggers.WFalloff);
+				ViewPos.Z += QuakePower(quakefactor, jiggers.RelIntensity.Z, jiggers.RelOffset.Z);
 			}
 			if (jiggers.Intensity.X != 0 || jiggers.Offset.X != 0)
 			{
-				ViewPos.X += QuakePower(quakefactor, jiggers.Intensity.X, jiggers.Offset.X, jiggers.Falloff, jiggers.WFalloff);
+				ViewPos.X += QuakePower(quakefactor, jiggers.Intensity.X, jiggers.Offset.X);
 			}
 			if (jiggers.Intensity.Y != 0 || jiggers.Offset.Y != 0)
 			{
-				ViewPos.Y += QuakePower(quakefactor, jiggers.Intensity.Y, jiggers.Offset.Y, jiggers.Falloff, jiggers.WFalloff);
+				ViewPos.Y += QuakePower(quakefactor, jiggers.Intensity.Y, jiggers.Offset.Y);
 			}
 			if (jiggers.Intensity.Z != 0 || jiggers.Offset.Z != 0)
 			{
-				ViewPos.Z += QuakePower(quakefactor, jiggers.Intensity.Z, jiggers.Offset.Z, jiggers.Falloff, jiggers.WFalloff);
+				ViewPos.Z += QuakePower(quakefactor, jiggers.Intensity.Z, jiggers.Offset.Z);
 			}
 		}
 	}
diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h
index 296383a3d5..3a419b112a 100644
--- a/src/thingdef/thingdef.h
+++ b/src/thingdef/thingdef.h
@@ -30,6 +30,7 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in
 bool CheckDeprecatedFlags(const AActor *actor, PClassActor *info, int index);
 const char *GetFlagName(unsigned int flagnum, int flagoffset);
 void ModActorFlag(AActor *actor, FFlagDef *fd, bool set);
+bool ModActorFlag(AActor *actor, FString &flagname, bool set, bool printerror = true);
 INTBOOL CheckActorFlag(const AActor *actor, FFlagDef *fd);
 INTBOOL CheckActorFlag(const AActor *owner, const char *flagname, bool printerror = true);
 
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index d520a0b9d8..642f132af9 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1422,7 +1422,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
 		damagetype = self->DamageType;
 	}
 
-	int count = P_RadiusAttack (self, self->target, damage, distance, damagetype, flags, fulldmgdistance);
+	int pflags = 0;
+	if (flags & XF_HURTSOURCE)	pflags |= RADF_HURTSOURCE;
+	if (flags & XF_NOTMISSILE)	pflags |= RADF_SOURCEISSPOT;
+
+	int count = P_RadiusAttack (self, self->target, damage, distance, damagetype, pflags, fulldmgdistance);
 	P_CheckSplash(self, distance);
 	if (alert && self->target != NULL && self->target->player != NULL)
 	{
@@ -4681,90 +4685,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag)
 	PARAM_STRING	(flagname);
 	PARAM_BOOL		(value);
 
-	const char *dot = strchr(flagname, '.');
-	FFlagDef *fd;
-	PClassActor *cls = self->GetClass();
-
-	if (dot != NULL)
-	{
-		FString part1(flagname.GetChars(), dot - flagname);
-		fd = FindFlag(cls, part1, dot + 1);
-	}
-	else
-	{
-		fd = FindFlag(cls, flagname, NULL);
-	}
-
-	if (fd != NULL)
-	{
-		bool kill_before, kill_after;
-		INTBOOL item_before, item_after;
-		INTBOOL secret_before, secret_after;
-
-		kill_before = self->CountsAsKill();
-		item_before = self->flags & MF_COUNTITEM;
-		secret_before = self->flags5 & MF5_COUNTSECRET;
-
-		if (fd->structoffset == -1)
-		{
-			HandleDeprecatedFlags(self, cls, value, fd->flagbit);
-		}
-		else
-		{
-			ActorFlags *flagp = (ActorFlags*) (((char*)self) + fd->structoffset);
-
-			// If these 2 flags get changed we need to update the blockmap and sector links.
-			bool linkchange = flagp == &self->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR);
-
-			if (linkchange) self->UnlinkFromWorld();
-			ModActorFlag(self, fd, value);
-			if (linkchange) self->LinkToWorld();
-		}
-		kill_after = self->CountsAsKill();
-		item_after = self->flags & MF_COUNTITEM;
-		secret_after = self->flags5 & MF5_COUNTSECRET;
-		// Was this monster previously worth a kill but no longer is?
-		// Or vice versa?
-		if (kill_before != kill_after)
-		{
-			if (kill_after)
-			{ // It counts as a kill now.
-				level.total_monsters++;
-			}
-			else
-			{ // It no longer counts as a kill.
-				level.total_monsters--;
-			}
-		}
-		// same for items
-		if (item_before != item_after)
-		{
-			if (item_after)
-			{ // It counts as an item now.
-				level.total_items++;
-			}
-			else
-			{ // It no longer counts as an item
-				level.total_items--;
-			}
-		}
-		// and secretd
-		if (secret_before != secret_after)
-		{
-			if (secret_after)
-			{ // It counts as an secret now.
-				level.total_secrets++;
-			}
-			else
-			{ // It no longer counts as an secret
-				level.total_secrets--;
-			}
-		}
-	}
-	else
-	{
-		Printf("Unknown flag '%s' in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars());
-	}
+	ModActorFlag(self, flagname, value);
 	return 0;
 }
 
diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp
index 8fceca8ee4..756c56a1a3 100644
--- a/src/thingdef/thingdef_data.cpp
+++ b/src/thingdef/thingdef_data.cpp
@@ -182,6 +182,7 @@ static FFlagDef ActorFlagDefs[]=
 	DEFINE_FLAG(MF4, BOSSDEATH, AActor, flags4),
 
 	DEFINE_FLAG(MF5, DONTDRAIN, AActor, flags5),
+	DEFINE_FLAG(MF5, GETOWNER, AActor, flags5),
 	DEFINE_FLAG(MF5, NODROPOFF, AActor, flags5),
 	DEFINE_FLAG(MF5, NOFORWARDFALL, AActor, flags5),
 	DEFINE_FLAG(MF5, COUNTSECRET, AActor, flags5),
diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp
index 372f444cd3..f6ad511afe 100644
--- a/src/thingdef/thingdef_properties.cpp
+++ b/src/thingdef/thingdef_properties.cpp
@@ -162,6 +162,71 @@ void ModActorFlag(AActor *actor, FFlagDef *fd, bool set)
 #endif
 }
 
+//==========================================================================
+//
+// Finds a flag by name and sets or clears it
+//
+// Returns true if the flag was found for the actor; else returns false
+//
+//==========================================================================
+
+bool ModActorFlag(AActor *actor, FString &flagname, bool set, bool printerror)
+{
+	bool found = false;
+
+	if (actor != NULL)
+	{
+		const char *dot = strchr(flagname, '.');
+		FFlagDef *fd;
+		PClassActor *cls = actor->GetClass();
+
+		if (dot != NULL)
+		{
+			FString part1(flagname.GetChars(), dot - flagname);
+			fd = FindFlag(cls, part1, dot + 1);
+		}
+		else
+		{
+			fd = FindFlag(cls, flagname, NULL);
+		}
+
+		if (fd != NULL)
+		{
+			found = true;
+
+			if (actor->CountsAsKill() && actor->health > 0) --level.total_monsters;
+			if (actor->flags & MF_COUNTITEM) --level.total_items;
+			if (actor->flags5 & MF5_COUNTSECRET) --level.total_secrets;
+
+			if (fd->structoffset == -1)
+			{
+				HandleDeprecatedFlags(actor, cls, set, fd->flagbit);
+			}
+			else
+			{
+				ActorFlags *flagp = (ActorFlags*)(((char*)actor) + fd->structoffset);
+
+				// If these 2 flags get changed we need to update the blockmap and sector links.
+				bool linkchange = flagp == &actor->flags && (fd->flagbit == MF_NOBLOCKMAP || fd->flagbit == MF_NOSECTOR);
+
+				if (linkchange) actor->UnlinkFromWorld();
+				ModActorFlag(actor, fd, set);
+				if (linkchange) actor->LinkToWorld();
+			}
+
+			if (actor->CountsAsKill() && actor->health > 0) ++level.total_monsters;
+			if (actor->flags & MF_COUNTITEM) ++level.total_items;
+			if (actor->flags5 & MF5_COUNTSECRET) ++level.total_secrets;
+		}
+		else if (printerror)
+		{
+			DPrintf(DMSG_ERROR, "ACS/DECORATE: '%s' is not a flag in '%s'\n", flagname.GetChars(), cls->TypeName.GetChars());
+		}
+	}
+
+	return found;
+}
+
 //==========================================================================
 //
 // Returns whether an actor flag is true or not.
diff --git a/src/v_draw.cpp b/src/v_draw.cpp
index 89023d4bda..dada0cd57c 100644
--- a/src/v_draw.cpp
+++ b/src/v_draw.cpp
@@ -62,6 +62,14 @@
 #include "colormatcher.h"
 #include "r_data/colormaps.h"
 
+CUSTOM_CVAR(Int, uiscale, 2, CVAR_ARCHIVE | CVAR_NOINITCALL)
+{
+	if (StatusBar != NULL)
+	{
+		StatusBar->ScreenSizeChanged();
+	}
+}
+
 // [RH] Stretch values to make a 320x200 image best fit the screen
 // without using fractional steppings
 int CleanXfac, CleanYfac;
@@ -75,7 +83,7 @@ int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1;
 // FillSimplePoly uses this
 extern "C" short spanend[MAXHEIGHT];
 
-CVAR (Bool, hud_scale, false, CVAR_ARCHIVE);
+CVAR (Bool, hud_scale, true, CVAR_ARCHIVE);
 
 // For routines that take RGB colors, cache the previous lookup in case there
 // are several repetitions with the same color.
diff --git a/src/v_video.cpp b/src/v_video.cpp
index 0ee065bbe9..b9917a1cb6 100644
--- a/src/v_video.cpp
+++ b/src/v_video.cpp
@@ -65,6 +65,7 @@
 #include "menu/menu.h"
 #include "r_data/voxels.h"
 
+int active_con_scale();
 
 FRenderer *Renderer;
 
@@ -857,10 +858,20 @@ void DFrameBuffer::DrawRateStuff ()
 			int chars;
 			int rate_x;
 
+			int textScale = active_con_scale();
+			if (textScale == 0)
+				textScale = CleanXfac;
+
 			chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount);
-			rate_x = Width - ConFont->StringWidth(&fpsbuff[0]);
-			Clear (rate_x, 0, Width, ConFont->GetHeight(), GPalette.BlackIndex, 0);
-			DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], TAG_DONE);
+			rate_x = Width / textScale - ConFont->StringWidth(&fpsbuff[0]);
+			Clear (rate_x * textScale, 0, Width, ConFont->GetHeight() * textScale, GPalette.BlackIndex, 0);
+			if (textScale == 1)
+				DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0], TAG_DONE);
+			else
+				DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0],
+					DTA_VirtualWidth, screen->GetWidth() / textScale,
+					DTA_VirtualHeight, screen->GetHeight() / textScale,
+					DTA_KeepRatio, true, TAG_DONE);
 
 			DWORD thisSec = ms/1000;
 			if (LastSec < thisSec)
diff --git a/src/v_video.h b/src/v_video.h
index 7091c518d4..4f0a786751 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -522,4 +522,6 @@ inline bool Is54Aspect(int ratio) {
     return ratio == 4;
 }
 
+EXTERN_CVAR(Int, uiscale);
+
 #endif // __V_VIDEO_H__
diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu
index c7d19fd923..757d7bf93a 100644
--- a/wadsrc/static/language.enu
+++ b/wadsrc/static/language.enu
@@ -1807,6 +1807,7 @@ DSPLYMNU_STILLBOB 				= "View bob amount while not moving";
 HUDMNU_TITLE					= "HUD Options";
 HUDMNU_ALTHUD					= "Alternative HUD";
 HUDMNU_MESSAGE					= "Message Options";
+HUDMNU_UISCALE					= "User interface scale";
 HUDMNU_CROSSHAIR				= "Default Crosshair";
 HUDMNU_FORCECROSSHAIR			= "Force default crosshair";
 HUDMNU_GROWCROSSHAIR			= "Grow crosshair when picking up items";
@@ -1946,6 +1947,7 @@ MSGMNU_SHOWMESSAGES			= "Show messages";
 MSGMNU_SHOWOBITUARIES		= "Show obituaries";
 MSGMNU_SHOWSECRETS			= "Show secret notifications";
 MSGMNU_SCALETEXT			= "Scale text in high res";
+MSGMNU_SCALECONSOLE			= "Scale console";
 MSGMNU_MESSAGELEVEL			= "Minimum message level";
 MSGMNU_CENTERMESSAGES		= "Center messages";
 MSGMNU_MESSAGECOLORS		= "Message Colors";
@@ -2237,6 +2239,7 @@ OPTVAL_ANIMATED				= "Animated";
 OPTVAL_ROTATED				= "Rotated";
 OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colors only";
 OPTVAL_DOUBLE				= "Double";
+OPTVAL_TRIPLE				= "Triple";
 OPTVAL_QUADRUPLE			= "Quadruple";
 OPTVAL_ITEMPICKUP			= "Item Pickup";
 OPTVAL_OBITUARIES			= "Obituaries";
diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt
index 33cfd95add..dcdaa90b3f 100644
--- a/wadsrc/static/menudef.txt
+++ b/wadsrc/static/menudef.txt
@@ -768,6 +768,8 @@ OptionMenu "HUDOptions"
 	Submenu "$HUDMNU_ALTHUD",				"AltHudOptions"
 	Submenu "$HUDMNU_MESSAGE", 				"MessageOptions"
 	StaticText " "
+	Slider "$HUDMNU_UISCALE",				"uiscale", 0.0, 8.0, 1.0, 0
+	StaticText " "
 	Option "$HUDMNU_CROSSHAIR",				"crosshair", "Crosshairs"
 	Option "$HUDMNU_FORCECROSSHAIR",		"crosshairforce", "OnOff"
 	Option "$HUDMNU_GROWCROSSHAIR",			"crosshairgrow", "OnOff"
@@ -802,6 +804,7 @@ OptionValue "AMCoordinates"
 OptionValue "AltHUDScale"
 {
 	0, "$OPTVAL_OFF"
+	4, "$OPTVAL_ON"
 	1, "$OPTVAL_SCALETO640X400"
 	2, "$OPTVAL_PIXELDOUBLE"
 	3, "$OPTVAL_PIXELQUADRUPLE"
@@ -1124,6 +1127,15 @@ OptionValue ScaleValues
 	3, "$OPTVAL_QUADRUPLE"
 }
 
+OptionValue ConsoleScaleValues
+{
+	1, "$OPTVAL_OFF"
+	0, "$OPTVAL_ON"
+	2, "$OPTVAL_DOUBLE"
+	3, "$OPTVAL_TRIPLE"
+	4, "$OPTVAL_QUADRUPLE"
+}
+
 OptionValue MessageLevels
 {
 	0.0, "$OPTVAL_ITEMPICKUP"
@@ -1147,6 +1159,7 @@ OptionMenu MessageOptions
 	Option "$MSGMNU_SHOWOBITUARIES",			"show_obituaries", "OnOff"
 	Option "$MSGMNU_SHOWSECRETS",				"cl_showsecretmessage", "OnOff"
 	Option "$MSGMNU_SCALETEXT", 				"con_scaletext", "ScaleValues"
+	Option "$MSGMNU_SCALECONSOLE", 				"con_scale", "ConsoleScaleValues"
 	Option "$MSGMNU_MESSAGELEVEL", 				"msg", "MessageLevels"
 	Option "$MSGMNU_DEVELOPER", 				"developer", "DevMessageLevels"
 	Option "$MSGMNU_CENTERMESSAGES",			"con_centernotify", "OnOff"