diff --git a/src/r_draw.c b/src/r_draw.c
index f0a19a462848d02c54b07a8a481f11e0969ebef0..ac6d67bc7d4d1e12eb166dc84cac5e9613339c86 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -883,6 +883,39 @@ void R_DrawViewBorder(void)
 }
 #endif
 
+// R_CalcTiltedLighting
+// Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly.
+static INT32 tiltlighting[MAXVIDWIDTH];
+
+static void R_CalcTiltedLighting(fixed_t start, fixed_t end)
+{
+	// ZDoom uses a different lighting setup to us, and I couldn't figure out how to adapt their version
+	// of this function. Here's my own.
+	INT32 left = ds_x1, right = ds_x2;
+	fixed_t step = (end-start)/(ds_x2-ds_x1+1);
+	INT32 i;
+
+	// I wanna do some optimizing by checking for out-of-range segments on either side to fill in all at once,
+	// but I'm too bad at coding to not crash the game trying to do that. I guess this is fast enough for now...
+
+	for (i = left; i <= right; i++) {
+		tiltlighting[i] = (start += step) >> FRACBITS;
+		if (tiltlighting[i] < 0)
+			tiltlighting[i] = 0;
+		else if (tiltlighting[i] >= MAXLIGHTSCALE)
+			tiltlighting[i] = MAXLIGHTSCALE-1;
+	}
+}
+
+// Lighting is simple. It's just linear interpolation from start to end
+#define CALC_SLOPE_LIGHT { \
+	float planelightfloat = PLANELIGHTFLOAT; \
+	float lightstart, lightend; \
+	lightend = (iz + ds_szp->x*width) * planelightfloat; \
+	lightstart = iz * planelightfloat; \
+	R_CalcTiltedLighting(FloatToFixed(lightstart), FloatToFixed(lightend)); \
+}
+
 // ==========================================================================
 //                   INCLUDE 8bpp DRAWING CODE HERE
 // ==========================================================================
diff --git a/src/r_draw.h b/src/r_draw.h
index 2173c7a5a36e5c9b92063657aa833dbb5b457726..823fb4839b847be47a9b27f3604d1a9a626e04d7 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -193,13 +193,11 @@ void R_DrawTranslucentFloorSprite_8(void);
 void R_DrawTiltedFloorSprite_8(void);
 void R_DrawTiltedTranslucentFloorSprite_8(void);
 
-void R_CalcTiltedLighting(fixed_t start, fixed_t end);
-extern INT32 tiltlighting[MAXVIDWIDTH];
-
 void R_DrawTranslucentWaterSpan_8(void);
 void R_DrawTiltedTranslucentWaterSpan_8(void);
 
 void R_DrawFogSpan_8(void);
+void R_DrawTiltedFogSpan_8(void);
 
 // Lactozilla: Non-powers-of-two
 void R_DrawSpan_NPO2_8(void);
diff --git a/src/r_draw8.c b/src/r_draw8.c
index b8a63d5c042d7ce49f8480bac269b763c43f5dd6..c7209fa3e856ae1fb6f1b4c1ae4e8281841c44a0 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -623,29 +623,6 @@ void R_DrawSpan_8 (void)
 	}
 }
 
-// R_CalcTiltedLighting
-// Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly.
-INT32 tiltlighting[MAXVIDWIDTH];
-void R_CalcTiltedLighting(fixed_t start, fixed_t end)
-{
-	// ZDoom uses a different lighting setup to us, and I couldn't figure out how to adapt their version
-	// of this function. Here's my own.
-	INT32 left = ds_x1, right = ds_x2;
-	fixed_t step = (end-start)/(ds_x2-ds_x1+1);
-	INT32 i;
-
-	// I wanna do some optimizing by checking for out-of-range segments on either side to fill in all at once,
-	// but I'm too bad at coding to not crash the game trying to do that. I guess this is fast enough for now...
-
-	for (i = left; i <= right; i++) {
-		tiltlighting[i] = (start += step) >> FRACBITS;
-		if (tiltlighting[i] < 0)
-			tiltlighting[i] = 0;
-		else if (tiltlighting[i] >= MAXLIGHTSCALE)
-			tiltlighting[i] = MAXLIGHTSCALE-1;
-	}
-}
-
 /**	\brief The R_DrawTiltedSpan_8 function
 	Draw slopes! Holy sheit!
 */
@@ -668,17 +645,7 @@ void R_DrawTiltedSpan_8(void)
 
 	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
-	// Lighting is simple. It's just linear interpolation from start to end
-	{
-		float planelightfloat = PLANELIGHTFLOAT;
-		float lightstart, lightend;
-
-		lightend = (iz + ds_szp->x*width) * planelightfloat;
-		lightstart = iz * planelightfloat;
-
-		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
-		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
-	}
+	CALC_SLOPE_LIGHT
 
 	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
 	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
@@ -801,17 +768,7 @@ void R_DrawTiltedTranslucentSpan_8(void)
 
 	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
-	// Lighting is simple. It's just linear interpolation from start to end
-	{
-		float planelightfloat = PLANELIGHTFLOAT;
-		float lightstart, lightend;
-
-		lightend = (iz + ds_szp->x*width) * planelightfloat;
-		lightstart = iz * planelightfloat;
-
-		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
-		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
-	}
+	CALC_SLOPE_LIGHT
 
 	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
 	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
@@ -934,17 +891,7 @@ void R_DrawTiltedTranslucentWaterSpan_8(void)
 
 	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
-	// Lighting is simple. It's just linear interpolation from start to end
-	{
-		float planelightfloat = PLANELIGHTFLOAT;
-		float lightstart, lightend;
-
-		lightend = (iz + ds_szp->x*width) * planelightfloat;
-		lightstart = iz * planelightfloat;
-
-		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
-		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
-	}
+	CALC_SLOPE_LIGHT
 
 	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
 	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
@@ -1066,17 +1013,7 @@ void R_DrawTiltedSplat_8(void)
 
 	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
-	// Lighting is simple. It's just linear interpolation from start to end
-	{
-		float planelightfloat = PLANELIGHTFLOAT;
-		float lightstart, lightend;
-
-		lightend = (iz + ds_szp->x*width) * planelightfloat;
-		lightstart = iz * planelightfloat;
-
-		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
-		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
-	}
+	CALC_SLOPE_LIGHT
 
 	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
 	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
@@ -2034,6 +1971,27 @@ void R_DrawFogSpan_8(void)
 	}
 }
 
+/**	\brief The R_DrawTiltedFogSpan_8 function
+	Draws a tilted span with fogging.
+*/
+void R_DrawTiltedFogSpan_8(void)
+{
+	int width = ds_x2 - ds_x1;
+
+	UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
+
+	double iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
+
+	CALC_SLOPE_LIGHT
+
+	do
+	{
+		UINT8 *colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+		*dest = colormap[*dest];
+		dest++;
+	} while (--width >= 0);
+}
+
 /**	\brief The R_DrawFogColumn_8 function
 	Fog wall.
 */
diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c
index 71ec999486497c562214620fcd0510219daf2ce0..656e1b0981559f70e575be43a589de203bd9519e 100644
--- a/src/r_draw8_npo2.c
+++ b/src/r_draw8_npo2.c
@@ -111,17 +111,7 @@ void R_DrawTiltedSpan_NPO2_8(void)
 
 	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
-	// Lighting is simple. It's just linear interpolation from start to end
-	{
-		float planelightfloat = PLANELIGHTFLOAT;
-		float lightstart, lightend;
-
-		lightend = (iz + ds_szp->x*width) * planelightfloat;
-		lightstart = iz * planelightfloat;
-
-		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
-		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
-	}
+	CALC_SLOPE_LIGHT
 
 	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
 	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
@@ -311,17 +301,7 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void)
 
 	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
-	// Lighting is simple. It's just linear interpolation from start to end
-	{
-		float planelightfloat = PLANELIGHTFLOAT;
-		float lightstart, lightend;
-
-		lightend = (iz + ds_szp->x*width) * planelightfloat;
-		lightstart = iz * planelightfloat;
-
-		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
-		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
-	}
+	CALC_SLOPE_LIGHT
 
 	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
 	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
@@ -509,17 +489,7 @@ void R_DrawTiltedSplat_NPO2_8(void)
 
 	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
-	// Lighting is simple. It's just linear interpolation from start to end
-	{
-		float planelightfloat = PLANELIGHTFLOAT;
-		float lightstart, lightend;
-
-		lightend = (iz + ds_szp->x*width) * planelightfloat;
-		lightstart = iz * planelightfloat;
-
-		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
-		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
-	}
+	CALC_SLOPE_LIGHT
 
 	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
 	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
@@ -1427,17 +1397,7 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void)
 
 	iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
 
-	// Lighting is simple. It's just linear interpolation from start to end
-	{
-		float planelightfloat = PLANELIGHTFLOAT;
-		float lightstart, lightend;
-
-		lightend = (iz + ds_szp->x*width) * planelightfloat;
-		lightstart = iz * planelightfloat;
-
-		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
-		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
-	}
+	CALC_SLOPE_LIGHT
 
 	uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx);
 	vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx);
diff --git a/src/r_plane.c b/src/r_plane.c
index d844048ae54b557d2900a04657100c0ebcc73c5d..d900313f6e29a12cb83b70c1328b36061769c6c1 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -262,6 +262,61 @@ static void R_MapTiltedPlane(INT32 y, INT32 x1, INT32 x2)
 	spanfunc();
 }
 
+static void R_MapFogPlane(INT32 y, INT32 x1, INT32 x2)
+{
+	fixed_t distance;
+	size_t pindex;
+
+#ifdef RANGECHECK
+	if (x2 < x1 || x1 < 0 || x2 >= viewwidth || y > viewheight)
+		I_Error("R_MapFogPlane: %d, %d at %d", x1, x2, y);
+#endif
+
+	if (x1 >= vid.width)
+		x1 = vid.width - 1;
+
+	if (planeheight != cachedheight[y])
+		distance = FixedMul(planeheight, yslope[y]);
+	else
+		distance = cacheddistance[y];
+
+	pindex = distance >> LIGHTZSHIFT;
+	if (pindex >= MAXLIGHTZ)
+		pindex = MAXLIGHTZ - 1;
+
+	ds_colormap = planezlight[pindex];
+	if (currentplane->extra_colormap)
+		ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps);
+
+	ds_y = y;
+	ds_x1 = x1;
+	ds_x2 = x2;
+
+	spanfunc();
+}
+
+static void R_MapTiltedFogPlane(INT32 y, INT32 x1, INT32 x2)
+{
+#ifdef RANGECHECK
+	if (x2 < x1 || x1 < 0 || x2 >= viewwidth || y > viewheight)
+		I_Error("R_MapTiltedFogPlane: %d, %d at %d", x1, x2, y);
+#endif
+
+	if (x1 >= vid.width)
+		x1 = vid.width - 1;
+
+	if (currentplane->extra_colormap)
+		ds_colormap = currentplane->extra_colormap->colormap;
+	else
+		ds_colormap = colormaps;
+
+	ds_y = y;
+	ds_x1 = x1;
+	ds_x2 = x2;
+
+	spanfunc();
+}
+
 void R_ClearFFloorClips (void)
 {
 	INT32 i, p;
@@ -791,11 +846,11 @@ static inline void R_AdjustSlopeCoordinatesNPO2(vector3_t *origin)
 
 void R_DrawSinglePlane(visplane_t *pl)
 {
-	levelflat_t *levelflat;
 	INT32 light = 0;
 	INT32 x, stop;
 	ffloor_t *rover;
-	INT32 type, spanfunctype = BASEDRAWFUNC;
+	boolean fog = false;
+	INT32 spanfunctype = BASEDRAWFUNC;
 	void (*mapfunc)(INT32, INT32, INT32) = R_MapPlane;
 
 	if (!(pl->minx <= pl->maxx))
@@ -885,6 +940,7 @@ void R_DrawSinglePlane(visplane_t *pl)
 			}
 			else if (pl->ffloor->flags & FF_FOG)
 			{
+				fog = true;
 				spanfunctype = SPANDRAWFUNC_FOG;
 				light = (pl->lightlevel >> LIGHTSEGSHIFT);
 			}
@@ -892,28 +948,28 @@ void R_DrawSinglePlane(visplane_t *pl)
 
 			if (pl->ffloor->flags & FF_RIPPLE)
 			{
-				INT32 top, bottom;
-
 				planeripple.active = true;
 
 				if (spanfunctype == SPANDRAWFUNC_TRANS)
 				{
-					spanfunctype = SPANDRAWFUNC_WATER;
-
 					// Copy the current scene, ugh
-					top = pl->high-8;
-					bottom = pl->low+8;
+					INT32 top = pl->high-8;
+					INT32 bottom = pl->low+8;
 
 					if (top < 0)
 						top = 0;
 					if (bottom > vid.height)
 						bottom = vid.height;
 
+					spanfunctype = SPANDRAWFUNC_WATER;
+
 					// Only copy the part of the screen we need
 					VID_BlitLinearScreen((splitscreen && viewplayer == &players[secondarydisplayplayer]) ? screens[0] + (top+(vid.height>>1))*vid.width : screens[0]+((top)*vid.width), screens[1]+((top)*vid.width),
 										 vid.width, bottom-top,
 										 vid.width, vid.width);
 				}
+				else if (fog)
+					planeripple.active = false;
 			}
 		}
 		else
@@ -921,35 +977,40 @@ void R_DrawSinglePlane(visplane_t *pl)
 	}
 
 	currentplane = pl;
-	levelflat = &levelflats[pl->picnum];
 
-	/* :james: */
-	type = levelflat->type;
-	switch (type)
+	if (!fog)
 	{
-		case LEVELFLAT_NONE:
-			return;
-		case LEVELFLAT_FLAT:
-			ds_source = (UINT8 *)R_GetFlat(levelflat->u.flat.lumpnum);
-			R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum));
-			// Raw flats always have dimensions that are powers-of-two numbers.
-			ds_powersoftwo = true;
-			break;
-		default:
-			ds_source = (UINT8 *)R_GetLevelFlat(levelflat);
-			if (!ds_source)
+		levelflat_t *levelflat = &levelflats[pl->picnum];
+
+		/* :james: */
+		switch (levelflat->type)
+		{
+			case LEVELFLAT_NONE:
 				return;
-			// Check if this texture or patch has power-of-two dimensions.
-			if (R_CheckPowersOfTwo())
-				R_CheckFlatLength(ds_flatwidth * ds_flatheight);
-	}
+			case LEVELFLAT_FLAT:
+				ds_source = (UINT8 *)R_GetFlat(levelflat->u.flat.lumpnum);
+				R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum));
+				// Raw flats always have dimensions that are powers-of-two numbers.
+				ds_powersoftwo = true;
+				break;
+			default:
+				ds_source = (UINT8 *)R_GetLevelFlat(levelflat);
+				if (!ds_source)
+					return;
+				// Check if this texture or patch has power-of-two dimensions.
+				if (R_CheckPowersOfTwo())
+					R_CheckFlatLength(ds_flatwidth * ds_flatheight);
+		}
 
-	if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later
-		&& viewangle != pl->viewangle+pl->plangle)
-	{
-		memset(cachedheight, 0, sizeof (cachedheight));
-		viewangle = pl->viewangle+pl->plangle;
+		if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later
+			&& viewangle != pl->viewangle+pl->plangle)
+		{
+			memset(cachedheight, 0, sizeof (cachedheight));
+			viewangle = pl->viewangle+pl->plangle;
+		}
 	}
+	else
+		mapfunc = R_MapFogPlane;
 
 	xoffs = pl->xoffs;
 	yoffs = pl->yoffs;
@@ -962,14 +1023,19 @@ void R_DrawSinglePlane(visplane_t *pl)
 
 	if (pl->slope)
 	{
-		mapfunc = R_MapTiltedPlane;
-
-		if (!pl->plangle)
+		if (fog)
+			mapfunc = R_MapTiltedFogPlane;
+		else
 		{
-			if (ds_powersoftwo)
-				R_AdjustSlopeCoordinates(&pl->slope->o);
-			else
-				R_AdjustSlopeCoordinatesNPO2(&pl->slope->o);
+			mapfunc = R_MapTiltedPlane;
+
+			if (!pl->plangle)
+			{
+				if (ds_powersoftwo)
+					R_AdjustSlopeCoordinates(&pl->slope->o);
+				else
+					R_AdjustSlopeCoordinatesNPO2(&pl->slope->o);
+			}
 		}
 
 		if (planeripple.active)
@@ -999,6 +1065,9 @@ void R_DrawSinglePlane(visplane_t *pl)
 			case SPANDRAWFUNC_SPLAT:
 				spanfunctype = SPANDRAWFUNC_TILTEDSPLAT;
 				break;
+			case SPANDRAWFUNC_FOG:
+				spanfunctype = SPANDRAWFUNC_TILTEDFOG;
+				break;
 			default:
 				spanfunctype = SPANDRAWFUNC_TILTED;
 				break;
diff --git a/src/screen.c b/src/screen.c
index 770f1c8026aaf4fcb5dd9df97da55271f717b547..ead2590ac4bd28e10e47b9e77ddaa1837105d334 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -139,6 +139,7 @@ void SCR_SetDrawFuncs(void)
 		spanfuncs[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_8;
 		spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_8;
 		spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8;
+		spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawTiltedFogSpan_8;
 
 		// Lactozilla: Non-powers-of-two
 		spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8;
@@ -154,7 +155,6 @@ void SCR_SetDrawFuncs(void)
 		spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8;
 		spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_NPO2_8;
 		spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_NPO2_8;
-		spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed
 
 #ifdef RUSEASM
 		if (R_ASM)
diff --git a/src/screen.h b/src/screen.h
index 67880e2b964dc16a7693d754a6646bd031f14c04..9931785613cf9ae30d8c68a65f0685e5725194f7 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -156,6 +156,7 @@ enum
 	SPANDRAWFUNC_TILTEDWATER,
 
 	SPANDRAWFUNC_FOG,
+	SPANDRAWFUNC_TILTEDFOG,
 
 	SPANDRAWFUNC_MAX
 };