diff --git a/src/d_player.h b/src/d_player.h
index 755926480ae9c2b2b90383659ec079230e48a881..6df6689c5fcf4f1085511218d7f19047cd8a7c0f 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -245,7 +245,8 @@ typedef enum
 	CR_MINECART,
 	CR_ROLLOUT,
 	CR_PTERABYTE,
-	CR_DUSTDEVIL
+	CR_DUSTDEVIL,
+	CR_FAN
 } carrytype_t; // pw_carry
 
 // Player powers. (don't edit this comment)
diff --git a/src/deh_tables.c b/src/deh_tables.c
index e45d552c9e601461e5c29025d9e7cb662ce966c0..11d8b1a0147aebf3e1dfb3cb5251324ebd76d6e9 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -5119,6 +5119,7 @@ struct int_const_s const INT_CONST[] = {
 	{"CR_ROLLOUT",CR_ROLLOUT},
 	{"CR_PTERABYTE",CR_PTERABYTE},
 	{"CR_DUSTDEVIL",CR_DUSTDEVIL},
+	{"CR_FAN",CR_FAN},
 
 	// Ring weapons (ringweapons_t)
 	// Useful for A_GiveWeapon
diff --git a/src/p_map.c b/src/p_map.c
index cf13f8489f08d6acc8f9630d70ca9158fa3d691a..1f2733c5a8ffb1c635379d599b2404c37ae443b9 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -505,11 +505,12 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
 			if (flipval*object->momz > FixedMul(speed, spring->scale))
 				object->momz = flipval*FixedMul(speed, spring->scale);
 
-			if (p && !p->powers[pw_tailsfly]) // doesn't reset anim for Tails' flight
+			if (p && !p->powers[pw_tailsfly] && !p->powers[pw_carry]) // doesn't reset anim for Tails' flight
 			{
 				P_ResetPlayer(p);
-				if (p->panim != PA_FALL)
-					P_SetPlayerMobjState(object, S_PLAY_FALL);
+				P_SetPlayerMobjState(object, S_PLAY_FALL);
+				P_SetTarget(&object->tracer, spring);
+				p->powers[pw_carry] = CR_FAN;
 			}
 			break;
 		case MT_STEAM: // Steam
diff --git a/src/p_spec.c b/src/p_spec.c
index 0fb07b9bf445664b44390e5820d774633e264d03..e59fefcaf23b6c1a98bcfdc3b5a4533d456b54e8 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -4978,9 +4978,13 @@ static void P_EvaluateSpecialFlags(player_t *player, sector_t *sector, sector_t
 		if (player->mo->momz > mobjinfo[MT_FAN].mass)
 			player->mo->momz = mobjinfo[MT_FAN].mass;
 
-		P_ResetPlayer(player);
-		if (player->panim != PA_FALL)
+		if (!player->powers[pw_carry])
+		{
+			P_ResetPlayer(player);
 			P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
+			P_SetTarget(&player->mo->tracer, player->mo);
+			player->powers[pw_carry] = CR_FAN;
+		}
 	}
 	if (sector->specialflags & SSF_SUPERTRANSFORM)
 	{
diff --git a/src/p_user.c b/src/p_user.c
index 189319a0acdb6a8e16308d95ba000c5e82411399..06249d9ffd0a3577079cb8e07b536b05bb29db83 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -12633,6 +12633,29 @@ void P_PlayerAfterThink(player_t *player)
 
 				break;
 			}
+			case CR_FAN:
+			{
+				fixed_t zdist;
+				mobj_t *mo = player->mo, *fan = player->mo->tracer;
+
+				if (!(player->pflags & PF_JUMPSTASIS))
+					player->pflags |= PF_JUMPSTASIS;
+
+				if (fan->eflags & MFE_VERTICALFLIP)
+					zdist = (mo->z + mo->height) - (fan->z + fan->height);
+				else
+					zdist = mo->z - fan->z;
+
+				if ((fan->type != MT_FAN && !P_PlayerTouchingSectorSpecialFlag(player, SSF_FAN))
+				|| (fan->type == MT_FAN && (abs(mo->x - fan->x) > fan->radius || abs(mo->y - fan->y) > fan->radius || zdist > (fan->health << FRACBITS))))
+				{
+					P_SetTarget(&player->mo->tracer, NULL);
+					player->pflags &= ~PF_JUMPSTASIS;
+					player->powers[pw_carry] = CR_NONE;
+					break;
+				}
+				break;
+			}
 			case CR_ROLLOUT:
 			{
 				mobj_t *mo = player->mo, *rock = player->mo->tracer;
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index a27a5ebd2687b9e7c6dee529e3a40aa9c76f54e1..ab30cf0ca95297a84afe928517cb95bbb4a97410 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -1633,6 +1633,11 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 #ifdef HWRENDER
 	if (vid.glstate == VID_GL_LIBRARY_LOADED)
 		flags |= SDL_WINDOW_OPENGL;
+
+	// Without a 24-bit depth buffer many visuals are ruined by z-fighting.
+	// Some GPU drivers may give us a 16-bit depth buffer since the
+	// default value for SDL_GL_DEPTH_SIZE is 16.
+	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
 #endif
 
 	// Create a window