diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg
index 15e7685c3df2cfb11e935bb58a139859976cb1f0..d40f2a373897e235024e55416578b0cd639d6ef7 100644
--- a/extras/conf/udb/Includes/SRB222_linedefs.cfg
+++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg
@@ -2453,6 +2453,12 @@ udmf
 				default = 255;
 			}
 			arg2
+			{
+				title = "Blending mode";
+				type = 11;
+				enum = "blendmodes";
+			}
+			arg3
 			{
 				title = "Appearance";
 				type = 12;
@@ -2466,7 +2472,7 @@ udmf
 					32 = "Cut cyan flat pixels";
 				}
 			}
-			arg3
+			arg4
 			{
 				title = "Tangibility";
 				type = 12;
@@ -2489,6 +2495,12 @@ udmf
 				default = 128;
 			}
 			arg2
+			{
+				title = "Blending mode";
+				type = 11;
+				enum = "blendmodes";
+			}
+			arg3
 			{
 				title = "Flags";
 				type = 12;
@@ -2556,12 +2568,18 @@ udmf
 				default = 255;
 			}
 			arg2
+			{
+				title = "Blending mode";
+				type = 11;
+				enum = "blendmodes";
+			}
+			arg3
 			{
 				title = "Tangibility";
 				type = 12;
 				enum = "tangibility";
 			}
-			arg3
+			arg4
 			{
 				title = "Flags";
 				type = 12;
@@ -2591,6 +2609,12 @@ udmf
 				default = 255;
 			}
 			arg2
+			{
+				title = "Blending mode";
+				type = 11;
+				enum = "blendmodes";
+			}
+			arg3
 			{
 				title = "Appearance";
 				type = 12;
@@ -2604,17 +2628,17 @@ udmf
 					32 = "Cut cyan flat pixels";
 				}
 			}
-			arg3
+			arg4
 			{
 				title = "Tangibility";
 				type = 12;
 				enum = "tangibility";
 			}
-			arg4
+			arg5
 			{
 				title = "Speed";
 			}
-			arg5
+			arg6
 			{
 				title = "Flags";
 				type = 12;
@@ -2669,6 +2693,12 @@ udmf
 				default = 255;
 			}
 			arg2
+			{
+				title = "Blending mode";
+				type = 11;
+				enum = "blendmodes";
+			}
+			arg3
 			{
 				title = "Appearance";
 				type = 12;
@@ -2755,6 +2785,12 @@ udmf
 				default = 255;
 			}
 			arg2
+			{
+				title = "Blending mode";
+				type = 11;
+				enum = "blendmodes";
+			}
+			arg3
 			{
 				title = "Bustable type";
 				type = 11;
@@ -2766,7 +2802,7 @@ udmf
 					3 = "Strong";
 				}
 			}
-			arg3
+			arg4
 			{
 				title = "Flags";
 				type = 12;
@@ -2778,7 +2814,7 @@ udmf
 					8 = "Cut cyan flat pixels";
 				}
 			}
-			arg4
+			arg5
 			{
 				title = "Linedef executor tag";
 				type = 15;
@@ -2825,6 +2861,12 @@ udmf
 				default = 128;
 			}
 			arg2
+			{
+				title = "Blending mode";
+				type = 11;
+				enum = "blendmodes";
+			}
+			arg3
 			{
 				title = "Flags";
 				type = 12;
@@ -2851,6 +2893,12 @@ udmf
 				default = 255;
 			}
 			arg2
+			{
+				title = "Blending mode";
+				type = 11;
+				enum = "blendmodes";
+			}
+			arg3
 			{
 				title = "Flags";
 				type = 12;
diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index c46fff8223aa237637210a3f045f907232864691..e392014c8a21b855895fb86ea70e041a60cc398b 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -649,6 +649,15 @@ enums
 		1 = "Random (Weak)";
 		2 = "Random (Strong)";
 	}
+
+	blendmodes
+	{
+		0 = "Translucent";
+		1 = "Add";
+		2 = "Subtract";
+		3 = "Reverse subtract";
+		4 = "Modulate";
+	}
 }
 
 //Default things filters
diff --git a/src/p_setup.c b/src/p_setup.c
index dbbd99859e87834a103cd4f7d7a788bcd91df96e..15e7c6d09a35b3bcd603d9efe2ff5fbc0784f638 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -3282,6 +3282,24 @@ static line_t *P_FindPointPushLine(taglist_t *list)
 	return NULL;
 }
 
+static void P_SetBinaryFOFAlpha(line_t *line)
+{
+	if (sides[line->sidenum[0]].toptexture > 0)
+	{
+		line->args[1] = sides[line->sidenum[0]].toptexture;
+		if (sides[line->sidenum[0]].toptexture >= 1001)
+		{
+			line->args[2] = (sides[line->sidenum[0]].toptexture/1000);
+			line->args[1] %= 1000;
+		}
+	}
+	else
+	{
+		line->args[1] = 128;
+		line->args[2] = TMB_TRANSLUCENT;
+	}
+}
+
 //For maps in binary format, converts setup of specials to UDMF format.
 static void P_ConvertBinaryMap(void)
 {
@@ -3562,36 +3580,33 @@ static void P_ConvertBinaryMap(void)
 			if (lines[i].special == 102)
 			{
 				if (lines[i].flags & ML_NOCLIMB)
-					lines[i].args[2] |= TMFA_INSIDES;
-				if (sides[lines[i].sidenum[0]].toptexture > 0)
-					lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-				else
-					lines[i].args[1] = 128;
+					lines[i].args[3] |= TMFA_INSIDES;
+				P_SetBinaryFOFAlpha(&lines[i]);
 
 				//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 				if (lines[i].args[1] == 256)
-					lines[i].args[2] |= TMFA_SPLAT;
+					lines[i].args[3] |= TMFA_SPLAT;
 			}
 			else
 				lines[i].args[1] = 255;
 
 			//Appearance
 			if (lines[i].special == 105)
-				lines[i].args[2] |= TMFA_NOPLANES|TMFA_NOSIDES;
+				lines[i].args[3] |= TMFA_NOPLANES|TMFA_NOSIDES;
 			else if (lines[i].special == 104)
-				lines[i].args[2] |= TMFA_NOSIDES;
+				lines[i].args[3] |= TMFA_NOSIDES;
 			else if (lines[i].special == 103)
-				lines[i].args[2] |= TMFA_NOPLANES;
+				lines[i].args[3] |= TMFA_NOPLANES;
 			if (lines[i].special != 100 && (lines[i].special != 104 || !(lines[i].flags & ML_NOCLIMB)))
-				lines[i].args[2] |= TMFA_NOSHADE;
+				lines[i].args[3] |= TMFA_NOSHADE;
 			if (lines[i].flags & ML_EFFECT6)
-				lines[i].args[2] |= TMFA_SPLAT;
+				lines[i].args[3] |= TMFA_SPLAT;
 
 			//Tangibility
 			if (lines[i].flags & ML_EFFECT1)
-				lines[i].args[3] |= TMFT_DONTBLOCKOTHERS;
+				lines[i].args[4] |= TMFT_DONTBLOCKOTHERS;
 			if (lines[i].flags & ML_EFFECT2)
-				lines[i].args[3] |= TMFT_DONTBLOCKPLAYER;
+				lines[i].args[4] |= TMFT_DONTBLOCKPLAYER;
 
 			lines[i].special = 100;
 			break;
@@ -3608,35 +3623,32 @@ static void P_ConvertBinaryMap(void)
 				lines[i].args[1] = 255;
 			else
 			{
-				if (sides[lines[i].sidenum[0]].toptexture > 0)
-					lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-				else
-					lines[i].args[1] = 128;
+				P_SetBinaryFOFAlpha(&lines[i]);
 
 				//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 				if (lines[i].args[1] == 256)
-					lines[i].args[2] |= TMFW_SPLAT;
+					lines[i].args[3] |= TMFW_SPLAT;
 			}
 
 			//No sides?
 			if (lines[i].special == 122 || lines[i].special == 123 || lines[i].special == 125)
-				lines[i].args[2] |= TMFW_NOSIDES;
+				lines[i].args[3] |= TMFW_NOSIDES;
 
 			//Flags
 			if (lines[i].flags & ML_NOCLIMB)
-				lines[i].args[2] |= TMFW_DOUBLESHADOW;
+				lines[i].args[3] |= TMFW_DOUBLESHADOW;
 			if (lines[i].flags & ML_EFFECT4)
-				lines[i].args[2] |= TMFW_COLORMAPONLY;
+				lines[i].args[3] |= TMFW_COLORMAPONLY;
 			if (!(lines[i].flags & ML_EFFECT5))
-				lines[i].args[2] |= TMFW_NORIPPLE;
+				lines[i].args[3] |= TMFW_NORIPPLE;
 
 			//Goo?
 			if (lines[i].special >= 124)
-				lines[i].args[2] |= TMFW_GOOWATER;
+				lines[i].args[3] |= TMFW_GOOWATER;
 
 			//Splat rendering?
 			if (lines[i].flags & ML_EFFECT6)
-				lines[i].args[2] |= TMFW_SPLAT;
+				lines[i].args[3] |= TMFW_SPLAT;
 
 			lines[i].special = 120;
 			break;
@@ -3653,41 +3665,38 @@ static void P_ConvertBinaryMap(void)
 			if (lines[i].special == 141 || lines[i].special == 142 || lines[i].special == 144 || lines[i].special == 145)
 			{
 				if (lines[i].flags & ML_NOCLIMB)
-					lines[i].args[2] |= TMFA_INSIDES;
-				if (sides[lines[i].sidenum[0]].toptexture > 0)
-					lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-				else
-					lines[i].args[1] = 128;
+					lines[i].args[3] |= TMFA_INSIDES;
+				P_SetBinaryFOFAlpha(&lines[i]);
 
 				//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 				if (lines[i].args[1] == 256)
-					lines[i].args[2] |= TMFA_SPLAT;
+					lines[i].args[3] |= TMFA_SPLAT;
 			}
 			else
 				lines[i].args[1] = 255;
 
 			//Appearance
 			if (lines[i].special == 142 || lines[i].special == 145)
-				lines[i].args[2] |= TMFA_NOSIDES;
+				lines[i].args[3] |= TMFA_NOSIDES;
 			else if (lines[i].special == 146)
-				lines[i].args[2] |= TMFA_NOPLANES;
+				lines[i].args[3] |= TMFA_NOPLANES;
 			if (lines[i].special != 146 && (lines[i].flags & ML_NOCLIMB))
-				lines[i].args[2] |= TMFA_NOSHADE;
+				lines[i].args[3] |= TMFA_NOSHADE;
 			if (lines[i].flags & ML_EFFECT6)
-				lines[i].args[2] |= TMFA_SPLAT;
+				lines[i].args[3] |= TMFA_SPLAT;
 
 			//Tangibility
 			if (lines[i].special <= 142)
-				lines[i].args[3] |= TMFT_INTANGIBLEBOTTOM;
+				lines[i].args[4] |= TMFT_INTANGIBLEBOTTOM;
 			else if (lines[i].special <= 145)
-				lines[i].args[3] |= TMFT_INTANGIBLETOP;
+				lines[i].args[4] |= TMFT_INTANGIBLETOP;
 			else
-				lines[i].args[3] |= TMFT_INTANGIBLEBOTTOM|TMFT_INTANGIBLETOP;
+				lines[i].args[4] |= TMFT_INTANGIBLEBOTTOM|TMFT_INTANGIBLETOP;
 
 			if (lines[i].flags & ML_EFFECT1)
-				lines[i].args[3] |= TMFT_DONTBLOCKOTHERS;
+				lines[i].args[4] |= TMFT_DONTBLOCKOTHERS;
 			if (lines[i].flags & ML_EFFECT2)
-				lines[i].args[3] |= TMFT_DONTBLOCKPLAYER;
+				lines[i].args[4] |= TMFT_DONTBLOCKPLAYER;
 
 			lines[i].special = 100;
 			break;
@@ -3727,38 +3736,35 @@ static void P_ConvertBinaryMap(void)
 			//Alpha
 			if (lines[i].special >= 174 && lines[i].special <= 175)
 			{
-				if (sides[lines[i].sidenum[0]].toptexture > 0)
-					lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-				else
-					lines[i].args[1] = 128;
+				P_SetBinaryFOFAlpha(&lines[i]);
 
 				//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 				if (lines[i].args[1] == 256)
-					lines[i].args[3] |= TMFC_SPLAT;
+					lines[i].args[4] |= TMFC_SPLAT;
 			}
 			else
 				lines[i].args[1] = 255;
 
 			if (lines[i].special >= 172 && lines[i].special <= 175)
 			{
-				lines[i].args[2] |= TMFT_INTANGIBLEBOTTOM;
+				lines[i].args[3] |= TMFT_INTANGIBLEBOTTOM;
 				if (lines[i].flags & ML_NOCLIMB)
-					lines[i].args[3] |= TMFC_NOSHADE;
+					lines[i].args[4] |= TMFC_NOSHADE;
 			}
 
 			if (lines[i].special % 2 == 1)
-				lines[i].args[3] |= TMFC_NORETURN;
+				lines[i].args[4] |= TMFC_NORETURN;
 			if (lines[i].special == 176 || lines[i].special == 177 || lines[i].special == 180)
-				lines[i].args[3] |= TMFC_AIRBOB;
+				lines[i].args[4] |= TMFC_AIRBOB;
 			if (lines[i].special >= 176 && lines[i].special <= 179)
-				lines[i].args[3] |= TMFC_FLOATBOB;
+				lines[i].args[4] |= TMFC_FLOATBOB;
 			if (lines[i].flags & ML_EFFECT6)
-				lines[i].args[3] |= TMFC_SPLAT;
+				lines[i].args[4] |= TMFC_SPLAT;
 
 			if (lines[i].flags & ML_EFFECT1)
-				lines[i].args[2] |= TMFT_DONTBLOCKOTHERS;
+				lines[i].args[3] |= TMFT_DONTBLOCKOTHERS;
 			if (lines[i].flags & ML_EFFECT2)
-				lines[i].args[2] |= TMFT_DONTBLOCKPLAYER;
+				lines[i].args[3] |= TMFT_DONTBLOCKPLAYER;
 
 			lines[i].special = 170;
 			break;
@@ -3773,44 +3779,41 @@ static void P_ConvertBinaryMap(void)
 			//Translucency
 			if (lines[i].special == 192 || lines[i].special == 195)
 			{
-				if (sides[lines[i].sidenum[0]].toptexture > 0)
-					lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-				else
-					lines[i].args[1] = 128;
+				P_SetBinaryFOFAlpha(&lines[i]);
 
 				//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 				if (lines[i].args[1] == 256)
-					lines[i].args[2] |= TMFA_SPLAT;
+					lines[i].args[3] |= TMFA_SPLAT;
 			}
 			else
 				lines[i].args[1] = 255;
 
 			//Appearance
 			if (lines[i].special == 193)
-				lines[i].args[2] |= TMFA_NOPLANES|TMFA_NOSIDES;
+				lines[i].args[3] |= TMFA_NOPLANES|TMFA_NOSIDES;
 			if (lines[i].special >= 194)
-				lines[i].args[2] |= TMFA_INSIDES;
+				lines[i].args[3] |= TMFA_INSIDES;
 			if (lines[i].special != 190 && (lines[i].special <= 193 || lines[i].flags & ML_NOCLIMB))
-				lines[i].args[2] |= TMFA_NOSHADE;
+				lines[i].args[3] |= TMFA_NOSHADE;
 			if (lines[i].flags & ML_EFFECT6)
-				lines[i].args[2] |= TMFA_SPLAT;
+				lines[i].args[3] |= TMFA_SPLAT;
 
 			//Tangibility
 			if (lines[i].flags & ML_EFFECT1)
-				lines[i].args[3] |= TMFT_DONTBLOCKOTHERS;
+				lines[i].args[4] |= TMFT_DONTBLOCKOTHERS;
 			if (lines[i].flags & ML_EFFECT2)
-				lines[i].args[3] |= TMFT_DONTBLOCKPLAYER;
+				lines[i].args[4] |= TMFT_DONTBLOCKPLAYER;
 			if (lines[i].special >= 194)
-				lines[i].args[3] |= TMFT_INTANGIBLEBOTTOM;
+				lines[i].args[4] |= TMFT_INTANGIBLEBOTTOM;
 
 			//Speed
-			lines[i].args[4] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS;
+			lines[i].args[5] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS;
 
 			//Flags
 			if (lines[i].flags & ML_BLOCKMONSTERS)
-				lines[i].args[5] |= TMFR_REVERSE;
+				lines[i].args[6] |= TMFR_REVERSE;
 			if (lines[i].flags & ML_BLOCKMONSTERS)
-				lines[i].args[5] |= TMFR_SPINDASH;
+				lines[i].args[6] |= TMFR_SPINDASH;
 
 			lines[i].special = 190;
 			break;
@@ -3833,27 +3836,24 @@ static void P_ConvertBinaryMap(void)
 			//Alpha
 			if (lines[i].special == 221)
 			{
-				if (sides[lines[i].sidenum[0]].toptexture > 0)
-					lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-				else
-					lines[i].args[1] = 128;
+				P_SetBinaryFOFAlpha(&lines[i]);
 
 				//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 				if (lines[i].args[1] == 256)
-					lines[i].args[2] |= TMFA_SPLAT;
+					lines[i].args[3] |= TMFA_SPLAT;
 			}
 			else
 				lines[i].args[1] = 255;
 
 			//Appearance
 			if (lines[i].special == 222)
-				lines[i].args[2] |= TMFA_NOPLANES;
+				lines[i].args[3] |= TMFA_NOPLANES;
 			if (lines[i].special == 221)
-				lines[i].args[2] |= TMFA_INSIDES;
+				lines[i].args[3] |= TMFA_INSIDES;
 			if (lines[i].special != 220 && !(lines[i].flags & ML_NOCLIMB))
-				lines[i].args[2] |= TMFA_NOSHADE;
+				lines[i].args[3] |= TMFA_NOSHADE;
 			if (lines[i].flags & ML_EFFECT6)
-				lines[i].args[2] |= TMFA_SPLAT;
+				lines[i].args[3] |= TMFA_SPLAT;
 
 			lines[i].special = 220;
             break;
@@ -3889,40 +3889,37 @@ static void P_ConvertBinaryMap(void)
 			//Alpha
 			if (lines[i].special == 253 || lines[i].special == 256)
 			{
-				if (sides[lines[i].sidenum[0]].toptexture > 0)
-					lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-				else
-					lines[i].args[1] = 128;
+				P_SetBinaryFOFAlpha(&lines[i]);
 
 				//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 				if (lines[i].args[1] == 256)
-					lines[i].args[3] |= TMFB_SPLAT;
+					lines[i].args[4] |= TMFB_SPLAT;
 			}
 			else
 				lines[i].args[1] = 255;
 
 			//Bustable type
 			if (lines[i].special <= 253)
-				lines[i].args[2] = TMFB_TOUCH;
+				lines[i].args[3] = TMFB_TOUCH;
 			else if (lines[i].special >= 255)
-				lines[i].args[2] = TMFB_SPIN;
+				lines[i].args[3] = TMFB_SPIN;
 			else if (lines[i].flags & ML_NOCLIMB)
-				lines[i].args[2] = TMFB_STRONG;
+				lines[i].args[3] = TMFB_STRONG;
 			else
-				lines[i].args[2] = TMFB_REGULAR;
+				lines[i].args[3] = TMFB_REGULAR;
 
 			//Flags
 			if (lines[i].flags & ML_EFFECT4)
-				lines[i].args[3] |= TMFB_PUSHABLES;
+				lines[i].args[4] |= TMFB_PUSHABLES;
 			if (lines[i].flags & ML_EFFECT5)
 			{
-				lines[i].args[3] |= TMFB_EXECUTOR;
-				lines[i].args[4] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS;
+				lines[i].args[4] |= TMFB_EXECUTOR;
+				lines[i].args[5] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS;
 			}
 			if (lines[i].special == 252 && lines[i].flags & ML_NOCLIMB)
-				lines[i].args[3] |= TMFB_ONLYBOTTOM;
+				lines[i].args[4] |= TMFB_ONLYBOTTOM;
 			if (lines[i].flags & ML_EFFECT6)
-				lines[i].args[3] |= TMFB_SPLAT;
+				lines[i].args[4] |= TMFB_SPLAT;
 
 			lines[i].special = 254;
 			break;
@@ -3937,17 +3934,14 @@ static void P_ConvertBinaryMap(void)
 			lines[i].args[0] = tag;
 
 			//Alpha
-			if (sides[lines[i].sidenum[0]].toptexture > 0)
-				lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-			else
-				lines[i].args[1] = 128;
+			P_SetBinaryFOFAlpha(&lines[i]);
 
 			//Flags
 			if (lines[i].flags & ML_EFFECT1)
-				lines[i].args[2] = TMFL_NOBOSSES;
+				lines[i].args[3] |= TMFL_NOBOSSES;
 			//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 			if (lines[i].flags & ML_EFFECT6 || lines[i].args[1] == 256)
-				lines[i].args[2] = TMFL_SPLAT;
+				lines[i].args[3] |= TMFL_SPLAT;
 
 			break;
 		case 259: //Custom FOF
@@ -3955,20 +3949,17 @@ static void P_ConvertBinaryMap(void)
 				I_Error("Custom FOF (tag %d) found without a linedef back side!", tag);
 
 			lines[i].args[0] = tag;
-			lines[i].args[2] = sides[lines[i].sidenum[1]].toptexture;
+			lines[i].args[3] = sides[lines[i].sidenum[1]].toptexture;
 			if (lines[i].flags & ML_EFFECT6)
-				lines[i].args[2] |= FF_SPLAT;
-			lines[i].args[3] = sides[lines[i].sidenum[1]].midtexture;
-			if (lines[i].args[2] & FF_TRANSLUCENT)
+				lines[i].args[3] |= FF_SPLAT;
+			lines[i].args[4] = sides[lines[i].sidenum[1]].midtexture;
+			if (lines[i].args[3] & FF_TRANSLUCENT)
 			{
-				if (sides[lines[i].sidenum[0]].toptexture > 0)
-					lines[i].args[1] = sides[lines[i].sidenum[0]].toptexture;
-				else
-					lines[i].args[1] = 128;
+				P_SetBinaryFOFAlpha(&lines[i]);
 
 				//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
 				if (lines[i].args[1] == 256)
-					lines[i].args[2] |= FF_SPLAT;
+					lines[i].args[3] |= FF_SPLAT;
 			}
 			else
 				lines[i].args[1] = 255;
diff --git a/src/p_spec.c b/src/p_spec.c
index 1220edf8f0e0fff1c1c924d00d566ee73eb7894a..9358d67660e033496eb4a2500fdf5300febf8d44 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -115,7 +115,7 @@ static void Add_ColormapFader(sector_t *sector, extracolormap_t *source_exc, ext
 static void P_AddBlockThinker(sector_t *sec, line_t *sourceline);
 static void P_AddFloatThinker(sector_t *sec, UINT16 tag, line_t *sourceline);
 //static void P_AddBridgeThinker(line_t *sourceline, sector_t *sec);
-static void P_AddFakeFloorsByLine(size_t line, INT32 alpha, ffloortype_e ffloorflags, thinkerlist_t *secthinkers);
+static void P_AddFakeFloorsByLine(size_t line, INT32 alpha, UINT8 blendmode, ffloortype_e ffloorflags, thinkerlist_t *secthinkers);
 static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec);
 static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer);
 static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee, UINT8 reverse);
@@ -5490,12 +5490,13 @@ static inline void P_AddFFloorToList(sector_t *sec, ffloor_t *fflr)
   * \param sec2        Control sector.
   * \param master      Control linedef.
   * \param alpha       Alpha value (0-255).
+  * \param blendmode   Blending mode.
   * \param flags       Options affecting this 3Dfloor.
   * \param secthinkers List of relevant thinkers sorted by sector. May be NULL.
   * \return Pointer to the new 3Dfloor.
   * \sa P_AddFFloor, P_AddFakeFloorsByLine, P_SpawnSpecials
   */
-static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, INT32 alpha, ffloortype_e flags, thinkerlist_t *secthinkers)
+static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, INT32 alpha, UINT8 blendmode, ffloortype_e flags, thinkerlist_t *secthinkers)
 {
 	ffloor_t *fflr;
 	thinker_t *th;
@@ -5621,15 +5622,29 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, I
 	{
 		fflr->flags |= FF_TRANSLUCENT;
 		fflr->spawnflags = fflr->flags;
-
-		if (sides[master->sidenum[0]].toptexture >= 1001)
-		{
-			fflr->blend = (sides[master->sidenum[0]].toptexture/1000)+1; // becomes an AST
-			fflr->alpha %= 1000;
-		}
 	}
 	fflr->spawnalpha = fflr->alpha; // save for netgames
 
+	switch (blendmode)
+	{
+		case TMB_TRANSLUCENT:
+		default:
+			fflr->blend = AST_TRANSLUCENT;
+			break;
+		case TMB_ADD:
+			fflr->blend = AST_ADD;
+			break;
+		case TMB_SUBTRACT:
+			fflr->blend = AST_SUBTRACT;
+			break;
+		case TMB_REVERSESUBTRACT:
+			fflr->blend = AST_REVERSESUBTRACT;
+			break;
+		case TMB_MODULATE:
+			fflr->blend = AST_MODULATE;
+			break;
+	}
+
 	if (flags & FF_QUICKSAND)
 		CheckForQuicksand = true;
 
@@ -6455,109 +6470,109 @@ void P_SpawnSpecials(boolean fromnetsave)
 				ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL;
 
 				//Appearance settings
-				if (lines[i].args[2] & TMFA_NOPLANES)
+				if (lines[i].args[3] & TMFA_NOPLANES)
 					ffloorflags &= ~FF_RENDERPLANES;
-				if (lines[i].args[2] & TMFA_NOSIDES)
+				if (lines[i].args[3] & TMFA_NOSIDES)
 					ffloorflags &= ~FF_RENDERSIDES;
-				if (lines[i].args[2] & TMFA_INSIDES)
+				if (lines[i].args[3] & TMFA_INSIDES)
 				{
 					if (ffloorflags & FF_RENDERPLANES)
 						ffloorflags |= FF_BOTHPLANES;
 					if (ffloorflags & FF_RENDERSIDES)
 						ffloorflags |= FF_ALLSIDES;
 				}
-				if (lines[i].args[2] & TMFA_ONLYINSIDES)
+				if (lines[i].args[3] & TMFA_ONLYINSIDES)
 				{
 					if (ffloorflags & FF_RENDERPLANES)
 						ffloorflags |= FF_INVERTPLANES;
 					if (ffloorflags & FF_RENDERSIDES)
 						ffloorflags |= FF_INVERTSIDES;
 				}
-				if (lines[i].args[2] & TMFA_NOSHADE)
+				if (lines[i].args[3] & TMFA_NOSHADE)
 					ffloorflags |= FF_NOSHADE;
-				if (lines[i].args[2] & TMFA_SPLAT)
+				if (lines[i].args[3] & TMFA_SPLAT)
 					ffloorflags |= FF_SPLAT;
 
 				//Tangibility settings
-				if (lines[i].args[3] & TMFT_INTANGIBLETOP)
+				if (lines[i].args[4] & TMFT_INTANGIBLETOP)
 					ffloorflags |= FF_REVERSEPLATFORM;
-				if (lines[i].args[3] & TMFT_INTANGIBLEBOTTOM)
+				if (lines[i].args[4] & TMFT_INTANGIBLEBOTTOM)
 					ffloorflags |= FF_PLATFORM;
-				if (lines[i].args[3] & TMFT_DONTBLOCKPLAYER)
+				if (lines[i].args[4] & TMFT_DONTBLOCKPLAYER)
 					ffloorflags &= ~FF_BLOCKPLAYER;
-				if (lines[i].args[3] & TMFT_DONTBLOCKOTHERS)
+				if (lines[i].args[4] & TMFT_DONTBLOCKOTHERS)
 					ffloorflags &= ~FF_BLOCKOTHERS;
 
 				//Cutting options
 				if (ffloorflags & FF_RENDERALL)
 				{
 					//If translucent or player can enter it, cut inner walls
-					if ((lines[i].args[1] < 255) || (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE))
+					if ((lines[i].args[1] < 255) || (lines[i].args[4] & TMFT_VISIBLEFROMINSIDE))
 						ffloorflags |= FF_CUTEXTRA|FF_EXTRA;
 					else
 						ffloorflags |= FF_CUTLEVEL;
 				}
 
-				P_AddFakeFloorsByLine(i, lines[i].args[1], ffloorflags, secthinkers);
+				P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers);
 				break;
 
 			case 120: // FOF (water)
 				ffloorflags = FF_EXISTS|FF_RENDERPLANES|FF_SWIMMABLE|FF_BOTHPLANES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES;
-				if (!(lines[i].args[2] & TMFW_NOSIDES))
+				if (!(lines[i].args[3] & TMFW_NOSIDES))
 					ffloorflags |= FF_RENDERSIDES|FF_ALLSIDES;
-				if (lines[i].args[2] & TMFW_DOUBLESHADOW)
+				if (lines[i].args[3] & TMFW_DOUBLESHADOW)
 					ffloorflags |= FF_DOUBLESHADOW;
-				if (lines[i].args[2] & TMFW_COLORMAPONLY)
+				if (lines[i].args[3] & TMFW_COLORMAPONLY)
 					ffloorflags |= FF_COLORMAPONLY;
-				if (!(lines[i].args[2] & TMFW_NORIPPLE))
+				if (!(lines[i].args[3] & TMFW_NORIPPLE))
 					ffloorflags |= FF_RIPPLE;
-				if (lines[i].args[2] & TMFW_GOOWATER)
+				if (lines[i].args[3] & TMFW_GOOWATER)
 					ffloorflags |= FF_GOOWATER;
-				if (lines[i].args[2] & TMFW_SPLAT)
+				if (lines[i].args[3] & TMFW_SPLAT)
 					ffloorflags |= FF_SPLAT;
-				P_AddFakeFloorsByLine(i, lines[i].args[1], ffloorflags, secthinkers);
+				P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers);
 				break;
 
 			case 150: // FOF (Air bobbing)
-				P_AddFakeFloorsByLine(i, 0xff, FF_EXISTS|FF_SOLID|FF_RENDERALL, secthinkers);
+				P_AddFakeFloorsByLine(i, 0xff, AST_COPY, FF_EXISTS|FF_SOLID|FF_RENDERALL, secthinkers);
 				P_AddAirbob(lines[i].frontsector, lines[i].args[0], lines[i].args[1] << FRACBITS, !!(lines[i].args[2] & TMFB_REVERSE), !!(lines[i].args[2] & TMFB_SPINDASH), !!(lines[i].args[2] & TMFB_DYNAMIC));
 				break;
 
 			case 160: // FOF (Water bobbing)
-				P_AddFakeFloorsByLine(i, 0xff, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB, secthinkers);
+				P_AddFakeFloorsByLine(i, 0xff, AST_COPY, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB, secthinkers);
 				break;
 
 			case 170: // FOF (Crumbling)
 				ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CRUMBLE;
 
 				//Tangibility settings
-				if (lines[i].args[2] & TMFT_INTANGIBLETOP)
+				if (lines[i].args[3] & TMFT_INTANGIBLETOP)
 					ffloorflags |= FF_REVERSEPLATFORM;
-				if (lines[i].args[2] & TMFT_INTANGIBLEBOTTOM)
+				if (lines[i].args[3] & TMFT_INTANGIBLEBOTTOM)
 					ffloorflags |= FF_PLATFORM;
-				if (lines[i].args[2] & TMFT_DONTBLOCKPLAYER)
+				if (lines[i].args[3] & TMFT_DONTBLOCKPLAYER)
 					ffloorflags &= ~FF_BLOCKPLAYER;
-				if (lines[i].args[2] & TMFT_DONTBLOCKOTHERS)
+				if (lines[i].args[3] & TMFT_DONTBLOCKOTHERS)
 					ffloorflags &= ~FF_BLOCKOTHERS;
 
 				//Flags
-				if (lines[i].args[3] & TMFC_NOSHADE)
+				if (lines[i].args[4] & TMFC_NOSHADE)
 					ffloorflags |= FF_NOSHADE;
-				if (lines[i].args[3] & TMFC_NORETURN)
+				if (lines[i].args[4] & TMFC_NORETURN)
 					ffloorflags |= FF_NORETURN;
-				if (lines[i].args[3] & TMFC_FLOATBOB)
+				if (lines[i].args[4] & TMFC_FLOATBOB)
 					ffloorflags |= FF_FLOATBOB;
-				if (lines[i].args[3] & TMFC_SPLAT)
+				if (lines[i].args[4] & TMFC_SPLAT)
 					ffloorflags |= FF_SPLAT;
 
 				//If translucent or player can enter it, cut inner walls
-				if (lines[i].args[1] < 0xff || (lines[i].args[2] & TMFT_VISIBLEFROMINSIDE))
+				if (lines[i].args[1] < 0xff || (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE))
 					ffloorflags |= FF_CUTEXTRA|FF_EXTRA;
 				else
 					ffloorflags |= FF_CUTLEVEL;
 
 				//If player can enter it, render insides
-				if (lines[i].args[2] & TMFT_VISIBLEFROMINSIDE)
+				if (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE)
 				{
 					if (ffloorflags & FF_RENDERPLANES)
 						ffloorflags |= FF_BOTHPLANES;
@@ -6565,8 +6580,8 @@ void P_SpawnSpecials(boolean fromnetsave)
 						ffloorflags |= FF_ALLSIDES;
 				}
 
-				P_AddFakeFloorsByLine(i, lines[i].args[1], ffloorflags, secthinkers);
-				if (lines[i].args[3] & TMFC_AIRBOB)
+				P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers);
+				if (lines[i].args[4] & TMFC_AIRBOB)
 					P_AddAirbob(lines[i].frontsector, lines[i].args[0], 16*FRACUNIT, false, false, false);
 				break;
 
@@ -6578,50 +6593,50 @@ void P_SpawnSpecials(boolean fromnetsave)
 				ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL;
 
 				//Appearance settings
-				if (lines[i].args[2] & TMFA_NOPLANES)
+				if (lines[i].args[3] & TMFA_NOPLANES)
 					ffloorflags &= ~FF_RENDERPLANES;
-				if (lines[i].args[2] & TMFA_NOSIDES)
+				if (lines[i].args[3] & TMFA_NOSIDES)
 					ffloorflags &= ~FF_RENDERSIDES;
-				if (lines[i].args[2] & TMFA_INSIDES)
+				if (lines[i].args[3] & TMFA_INSIDES)
 				{
 					if (ffloorflags & FF_RENDERPLANES)
 						ffloorflags |= FF_BOTHPLANES;
 					if (ffloorflags & FF_RENDERSIDES)
 						ffloorflags |= FF_ALLSIDES;
 				}
-				if (lines[i].args[2] & TMFA_ONLYINSIDES)
+				if (lines[i].args[3] & TMFA_ONLYINSIDES)
 				{
 					if (ffloorflags & FF_RENDERPLANES)
 						ffloorflags |= FF_INVERTPLANES;
 					if (ffloorflags & FF_RENDERSIDES)
 						ffloorflags |= FF_INVERTSIDES;
 				}
-				if (lines[i].args[2] & TMFA_NOSHADE)
+				if (lines[i].args[3] & TMFA_NOSHADE)
 					ffloorflags |= FF_NOSHADE;
-				if (lines[i].args[2] & TMFA_SPLAT)
+				if (lines[i].args[3] & TMFA_SPLAT)
 					ffloorflags |= FF_SPLAT;
 
 				//Tangibility settings
-				if (lines[i].args[3] & TMFT_INTANGIBLETOP)
+				if (lines[i].args[4] & TMFT_INTANGIBLETOP)
 					ffloorflags |= FF_REVERSEPLATFORM;
-				if (lines[i].args[3] & TMFT_INTANGIBLEBOTTOM)
+				if (lines[i].args[4] & TMFT_INTANGIBLEBOTTOM)
 					ffloorflags |= FF_PLATFORM;
-				if (lines[i].args[3] & TMFT_DONTBLOCKPLAYER)
+				if (lines[i].args[4] & TMFT_DONTBLOCKPLAYER)
 					ffloorflags &= ~FF_BLOCKPLAYER;
-				if (lines[i].args[3] & TMFT_DONTBLOCKOTHERS)
+				if (lines[i].args[4] & TMFT_DONTBLOCKOTHERS)
 					ffloorflags &= ~FF_BLOCKOTHERS;
 
 				//Cutting options
 				if (ffloorflags & FF_RENDERALL)
 				{
 					//If translucent or player can enter it, cut inner walls
-					if ((lines[i].args[1] < 255) || (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE))
+					if ((lines[i].args[1] < 255) || (lines[i].args[4] & TMFT_VISIBLEFROMINSIDE))
 						ffloorflags |= FF_CUTEXTRA|FF_EXTRA;
 					else
 						ffloorflags |= FF_CUTLEVEL;
 				}
 
-				P_AddFakeFloorsByLine(i, lines[i].args[1], ffloorflags, secthinkers);
+				P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers);
 				P_AddRaiseThinker(lines[i].frontsector, lines[i].args[0], lines[i].args[4] << FRACBITS, ceilingtop, ceilingbottom, !!(lines[i].args[5] & TMFR_REVERSE), !!(lines[i].args[5] & TMFR_SPINDASH));
 				break;
 			}
@@ -6629,7 +6644,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 				ffloorflags = FF_EXISTS|FF_CUTSPRITES;
 				if (!lines[i].args[1])
 					ffloorflags |= FF_DOUBLESHADOW;
-				P_AddFakeFloorsByLine(i, 0xff, ffloorflags, secthinkers);
+				P_AddFakeFloorsByLine(i, 0xff, AST_COPY, ffloorflags, secthinkers);
 				break;
 
 			case 202: // Fog
@@ -6638,41 +6653,41 @@ void P_SpawnSpecials(boolean fromnetsave)
 				// SoM: Because it's fog, check for an extra colormap and set the fog flag...
 				if (sectors[sec].extra_colormap)
 					sectors[sec].extra_colormap->flags = CMF_FOG;
-				P_AddFakeFloorsByLine(i, 0xff, ffloorflags, secthinkers);
+				P_AddFakeFloorsByLine(i, 0xff, AST_COPY, ffloorflags, secthinkers);
 				break;
 
 			case 220: //Intangible
 				ffloorflags = FF_EXISTS|FF_RENDERALL|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES;
 
 				//Appearance settings
-				if (lines[i].args[2] & TMFA_NOPLANES)
+				if (lines[i].args[3] & TMFA_NOPLANES)
 					ffloorflags &= ~FF_RENDERPLANES;
-				if (lines[i].args[2] & TMFA_NOSIDES)
+				if (lines[i].args[3] & TMFA_NOSIDES)
 					ffloorflags &= ~FF_RENDERSIDES;
-				if (!(lines[i].args[2] & TMFA_INSIDES))
+				if (!(lines[i].args[3] & TMFA_INSIDES))
 				{
 					if (ffloorflags & FF_RENDERPLANES)
 						ffloorflags |= FF_BOTHPLANES;
 					if (ffloorflags & FF_RENDERSIDES)
 						ffloorflags |= FF_ALLSIDES;
 				}
-				if (lines[i].args[2] & TMFA_ONLYINSIDES)
+				if (lines[i].args[3] & TMFA_ONLYINSIDES)
 				{
 					if (ffloorflags & FF_RENDERPLANES)
 						ffloorflags |= FF_INVERTPLANES;
 					if (ffloorflags & FF_RENDERSIDES)
 						ffloorflags |= FF_INVERTSIDES;
 				}
-				if (lines[i].args[2] & TMFA_NOSHADE)
+				if (lines[i].args[3] & TMFA_NOSHADE)
 					ffloorflags |= FF_NOSHADE;
-				if (lines[i].args[2] & TMFA_SPLAT)
+				if (lines[i].args[3] & TMFA_SPLAT)
 					ffloorflags |= FF_SPLAT;
 
-				P_AddFakeFloorsByLine(i, lines[i].args[1], ffloorflags, secthinkers);
+				P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers);
 				break;
 
 			case 223: // FOF (intangible, invisible) - for combining specials in a sector
-				P_AddFakeFloorsByLine(i, 0xff, FF_EXISTS|FF_NOSHADE, secthinkers);
+				P_AddFakeFloorsByLine(i, 0xff, AST_COPY, FF_EXISTS|FF_NOSHADE, secthinkers);
 				break;
 
 			case 250: // Mario Block
@@ -6682,14 +6697,14 @@ void P_SpawnSpecials(boolean fromnetsave)
 				if (lines[i].args[1] & TMFM_INVISIBLE)
 					ffloorflags &= ~(FF_SOLID|FF_RENDERALL|FF_CUTLEVEL);
 
-				P_AddFakeFloorsByLine(i, 0xff, ffloorflags, secthinkers);
+				P_AddFakeFloorsByLine(i, 0xff, AST_COPY, ffloorflags, secthinkers);
 				break;
 
 			case 251: // A THWOMP!
 			{
 				UINT16 sound = (lines[i].stringargs[0]) ? get_number(lines[i].stringargs[0]) : sfx_thwomp;
 				P_AddThwompThinker(lines[i].frontsector, &lines[i], lines[i].args[1] << (FRACBITS - 3), lines[i].args[2] << (FRACBITS - 3), sound);
-				P_AddFakeFloorsByLine(i, 0xff, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers);
+				P_AddFakeFloorsByLine(i, 0xff, AST_COPY, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers);
 				break;
 			}
 
@@ -6701,7 +6716,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 				ffloorflags = FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP;
 
 				//Bustable type
-				switch (lines[i].args[2])
+				switch (lines[i].args[3])
 				{
 					case TMFB_TOUCH:
 						busttype = BT_TOUCH;
@@ -6718,13 +6733,13 @@ void P_SpawnSpecials(boolean fromnetsave)
 				}
 
 				//Flags
-				if (lines[i].args[3] & TMFB_PUSHABLES)
+				if (lines[i].args[4] & TMFB_PUSHABLES)
 					bustflags |= FB_PUSHABLES;
-				if (lines[i].args[3] & TMFB_EXECUTOR)
+				if (lines[i].args[4] & TMFB_EXECUTOR)
 					bustflags |= FB_EXECUTOR;
-				if (lines[i].args[3] & TMFB_ONLYBOTTOM)
+				if (lines[i].args[4] & TMFB_ONLYBOTTOM)
 					bustflags |= FB_ONLYBOTTOM;
-				if (lines[i].args[3] & TMFB_SPLAT)
+				if (lines[i].args[4] & TMFB_SPLAT)
 					ffloorflags |= FF_SPLAT;
 
 				if (busttype != BT_TOUCH || bustflags & FB_ONLYBOTTOM)
@@ -6732,12 +6747,12 @@ void P_SpawnSpecials(boolean fromnetsave)
 
 				TAG_ITER_SECTORS(lines[i].args[0], s)
 				{
-					ffloor_t *fflr = P_AddFakeFloor(&sectors[s], lines[i].frontsector, lines + i, lines[i].args[1], ffloorflags, secthinkers);
+					ffloor_t *fflr = P_AddFakeFloor(&sectors[s], lines[i].frontsector, lines + i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers);
 					if (!fflr)
 						continue;
 					fflr->bustflags = bustflags;
 					fflr->busttype = busttype;
-					fflr->busttag = lines[i].args[4];
+					fflr->busttag = lines[i].args[5];
 				}
 				break;
 			}
@@ -6748,7 +6763,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 
 				TAG_ITER_SECTORS(lines[i].args[0], s)
 				{
-					ffloor_t *fflr = P_AddFakeFloor(&sectors[s], lines[i].frontsector, lines + i, 0xff, ffloorflags, secthinkers);
+					ffloor_t *fflr = P_AddFakeFloor(&sectors[s], lines[i].frontsector, lines + i, 0xff, AST_COPY, ffloorflags, secthinkers);
 					if (!fflr)
 						continue;
 					fflr->sinkspeed = abs(lines[i].args[2]) << (FRACBITS - 1);
@@ -6758,28 +6773,28 @@ void P_SpawnSpecials(boolean fromnetsave)
 
 			case 258: // Laser block
 				ffloorflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT;
-				P_AddLaserThinker(lines[i].args[0], lines + i, !!(lines[i].args[2] & TMFL_NOBOSSES));
-				if (lines[i].args[2] & TMFL_SPLAT)
+				P_AddLaserThinker(lines[i].args[0], lines + i, !!(lines[i].args[3] & TMFL_NOBOSSES));
+				if (lines[i].args[3] & TMFL_SPLAT)
 					ffloorflags |= FF_SPLAT;
-				P_AddFakeFloorsByLine(i, lines[i].args[1], ffloorflags, secthinkers);
+				P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers);
 				break;
 
 			case 259: // Custom FOF
 				TAG_ITER_SECTORS(lines[i].args[0], s)
 				{
-					ffloor_t *fflr = P_AddFakeFloor(&sectors[s], lines[i].frontsector, lines + i, lines[i].args[1], lines[i].args[2], secthinkers);
+					ffloor_t *fflr = P_AddFakeFloor(&sectors[s], lines[i].frontsector, lines + i, lines[i].args[1], lines[i].args[2], lines[i].args[3], secthinkers);
 					if (!fflr)
 						continue;
 					if (!udmf) // Ugly backwards compatibility stuff
 					{
-						if (lines[i].args[2] & FF_QUICKSAND)
+						if (lines[i].args[3] & FF_QUICKSAND)
 						{
 							fflr->sinkspeed = abs(lines[i].dx) >> 1;
 							fflr->friction = abs(lines[i].dy) >> 6;
 						}
-						if (lines[i].args[2] & FF_BUSTUP)
+						if (lines[i].args[3] & FF_BUSTUP)
 						{
-							switch (lines[i].args[3] % TMFB_ONLYBOTTOM)
+							switch (lines[i].args[4] % TMFB_ONLYBOTTOM)
 							{
 								case TMFB_TOUCH:
 									fflr->busttype = BT_TOUCH;
@@ -6795,7 +6810,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 									break;
 							}
 
-							if (lines[i].args[3] & TMFB_ONLYBOTTOM)
+							if (lines[i].args[4] & TMFB_ONLYBOTTOM)
 								fflr->bustflags |= FB_ONLYBOTTOM;
 							if (lines[i].flags & ML_EFFECT4)
 								fflr->bustflags |= FB_PUSHABLES;
@@ -6870,7 +6885,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 						}
 					}
 
-					P_AddFakeFloorsByLine(i, dopacity, ffloorflags, secthinkers);
+					P_AddFakeFloorsByLine(i, dopacity, AST_TRANSLUCENT, ffloorflags, secthinkers);
 				}
 				break;
 
@@ -7159,12 +7174,13 @@ void P_SpawnSpecials(boolean fromnetsave)
   *
   * \param line        Control linedef to use.
   * \param alpha       Alpha value (0-255).
+  * \param blendmode   Blending mode.
   * \param ffloorflags 3Dfloor flags to use.
   * \param secthkiners Lists of thinkers sorted by sector. May be NULL.
   * \sa P_SpawnSpecials, P_AddFakeFloor
   * \author Graue <graue@oceanbase.org>
   */
-static void P_AddFakeFloorsByLine(size_t line, INT32 alpha, ffloortype_e ffloorflags, thinkerlist_t *secthinkers)
+static void P_AddFakeFloorsByLine(size_t line, INT32 alpha, UINT8 blendmode, ffloortype_e ffloorflags, thinkerlist_t *secthinkers)
 {
 	INT32 s;
 	mtag_t tag = lines[line].args[0];
@@ -7172,7 +7188,7 @@ static void P_AddFakeFloorsByLine(size_t line, INT32 alpha, ffloortype_e ffloorf
 
 	line_t* li = lines + line;
 	TAG_ITER_SECTORS(tag, s)
-		P_AddFakeFloor(&sectors[s], &sectors[sec], li, alpha, ffloorflags, secthinkers);
+		P_AddFakeFloor(&sectors[s], &sectors[sec], li, alpha, blendmode, ffloorflags, secthinkers);
 }
 
 /*
diff --git a/src/p_spec.h b/src/p_spec.h
index d02b5989f6e634e1f2d3a8a7a12116e3c176df41..40d7197fbb7885a463f5e78d0234a693a0a9f54c 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -448,7 +448,6 @@ typedef enum
 	TMPF_NONEXCLUSIVE = 1<<1,
 } textmappusherflags_t;
 
-
 typedef enum
 {
 	TMPP_NOZFADE      = 1,
@@ -456,6 +455,15 @@ typedef enum
 	TMPP_NONEXCLUSIVE = 1<<2,
 } textmappointpushflags_t;
 
+typedef enum
+{
+	TMB_TRANSLUCENT     = 0,
+	TMB_ADD             = 1,
+	TMB_SUBTRACT        = 2,
+	TMB_REVERSESUBTRACT = 3,
+	TMB_MODULATE        = 4,
+} textmapblendmodes_t;
+
 // GETSECSPECIAL (specialval, section)
 //
 // Pulls out the special # from a particular section.