diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index 52cd22322f1c93086462302c31291f7dcaf8aed4..4139fa967a3fa59ec5cb9dcebaa3e8a18a55f67a 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -226,6 +226,12 @@ universalfields
 			type = 3;
 			default = false;
 		}
+
+		friction
+		{
+			type = 0;
+			default = 0;
+		}
 	}
 
 	linedef
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 9f267d0719e0f12219571e6c8f8733dbe0ec12ab..a74c6fc9733d686beacfaefc6421292c60a8e4d0 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -50,6 +50,7 @@ enum sector_e {
 	sector_fslope,
 	sector_cslope,
 	sector_flags,
+	sector_friction,
 };
 
 static const char *const sector_opt[] = {
@@ -74,6 +75,7 @@ static const char *const sector_opt[] = {
 	"f_slope",
 	"c_slope",
 	"flags",
+	"friction",
 	NULL};
 
 enum subsector_e {
@@ -654,6 +656,9 @@ static int sector_get(lua_State *L)
 	case sector_flags: // flags
 		lua_pushinteger(L, sector->flags);
 		return 1;
+	case sector_friction: // friction
+		lua_pushinteger(L, sector->friction);
+		return 1;
 	}
 	return 0;
 }
@@ -681,6 +686,7 @@ static int sector_set(lua_State *L)
 	case sector_ffloors: // ffloors
 	case sector_fslope: // f_slope
 	case sector_cslope: // c_slope
+	case sector_friction: // friction
 	default:
 		return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]);
 	case sector_floorheight: { // floorheight
diff --git a/src/p_setup.c b/src/p_setup.c
index ec35ad824ab5c29b050ef3d66f0b7b5f95350850..85d4ee5dce59c11786ea7985692934591108aad9 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1674,6 +1674,8 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val)
 		sectors[i].flags |= MSF_INVERTPRECIP;
 	else if (fastcmp(param, "heatwave") && fastcmp("true", val))
 		sectors[i].flags |= MSF_HEATWAVE;
+	else if (fastcmp(param, "friction"))
+		sectors[i].friction = atol(val);
 }
 
 static void ParseTextmapSidedefParameter(UINT32 i, char *param, char *val)
@@ -4835,6 +4837,13 @@ static void P_ConvertBinaryMap(void)
 				lines[i].args[4] |= TMST_NONEXCLUSIVE;
 			lines[i].special = 510;
 			break;
+		case 540: //Floor friction
+		{
+			INT32 s;
+			TAG_ITER_SECTORS(tag, s)
+				sectors[s].friction = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS;
+			break;
+		}
 		case 541: //Wind
 		case 542: //Upwards wind
 		case 543: //Downwards wind
diff --git a/src/p_spec.c b/src/p_spec.c
index ef48fbf62565520862605afd6038d5ff7899f7e8..69b76aee75ec596adde6fc5df313cca35c6af15d 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -8184,40 +8184,40 @@ void T_Friction(friction_t *f)
 static void P_SpawnFriction(void)
 {
 	size_t i;
-	line_t *l = lines;
-	mtag_t tag;
-	register INT32 s;
-	fixed_t strength; // frontside texture offset controls magnitude
+	sector_t *s = sectors;
+
+	fixed_t strength; // friction value of sector
 	fixed_t friction; // friction value to be applied during movement
 	INT32 movefactor; // applied to each player move to simulate inertia
 
-	for (i = 0; i < numlines; i++, l++)
-		if (l->special == 540)
-		{
-			tag = Tag_FGet(&l->tags);
-			strength = sides[l->sidenum[0]].textureoffset>>FRACBITS;
-			if (strength > 0) // sludge
-				strength = strength*2; // otherwise, the maximum sludginess value is +967...
-
-			// The following might seem odd. At the time of movement,
-			// the move distance is multiplied by 'friction/0x10000', so a
-			// higher friction value actually means 'less friction'.
-			friction = ORIG_FRICTION - (0x1EB8*strength)/0x80; // ORIG_FRICTION is 0xE800
-
-			if (friction > FRACUNIT)
-				friction = FRACUNIT;
-			if (friction < 0)
-				friction = 0;
-
-			movefactor = FixedDiv(ORIG_FRICTION, friction);
-			if (movefactor < FRACUNIT)
-				movefactor = 8*movefactor - 7*FRACUNIT;
-			else
-				movefactor = FRACUNIT;
+	for (i = 0; i < numsectors; i++, s++)
+	{
+		if (!s->friction)
+			continue;
 
-			TAG_ITER_SECTORS(tag, s)
-				Add_Friction(friction, movefactor, s, -1);
-		}
+		strength = s->friction;
+		if (strength > 0) // sludge
+			strength = strength*2; // otherwise, the maximum sludginess value is +967...
+
+		// The following might seem odd. At the time of movement,
+		// the move distance is multiplied by 'friction/0x10000', so a
+		// higher friction value actually means 'less friction'.
+		friction = ORIG_FRICTION - (0x1EB8*strength)/0x80; // ORIG_FRICTION is 0xE800
+
+		if (friction > FRACUNIT)
+			friction = FRACUNIT;
+		if (friction < 0)
+			friction = 0;
+
+		movefactor = FixedDiv(ORIG_FRICTION, friction);
+		if (movefactor < FRACUNIT)
+			movefactor = 8*movefactor - 7*FRACUNIT;
+		else
+			movefactor = FRACUNIT;
+
+		Add_Friction(friction, movefactor, (INT32)(s-sectors), -1);
+
+	}
 }
 
 /*
diff --git a/src/r_defs.h b/src/r_defs.h
index 16c4ad64f7b9b821074adf97a4278feab387c613..105494bd70dd48dc971d52218fc20602d5717b07 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -371,6 +371,8 @@ typedef struct sector_s
 	boolean verticalflip; // If gravity < 0, then allow flipped physics
 	sectorflags_t flags;
 
+	INT32 friction;
+
 	// Sprite culling feature
 	struct line_s *cullheight;