diff --git a/src/d_player.h b/src/d_player.h
index 79f2a3b924ac5781f9312a7f5523cbe9d4deef7e..7193ce591ee6d3fb5a86c9b31ed2028b21e5b5dd 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -243,7 +243,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 b907e2206d8685ff4285fe9afdc733ba45532842..54f3288f06fb74941ef909d0d9555075778e847c 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -4984,6 +4984,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 b934e3255323e86a7ae572342fa27f3a84db516c..da68b9511e76937892a967d839be1575bbe99a66 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -498,11 +498,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 5b9e05c61f1e91727a9201403eafaa0cbcc825e1..00fe3ca0e5a0517cc14d8553376c7134f751c195 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -4662,9 +4662,13 @@ DoneSection2:
 			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;
+			}
 			break;
 
 		case 6: // Super Sonic transformer
diff --git a/src/p_user.c b/src/p_user.c
index 2dcc21009079702dcb92d9fb031c58bdadf44130..f0172ce6bbbfa8913ce72c6c77f5321acb770753 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -12694,6 +12694,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_PlayerTouchingSectorSpecial(player, 4, 5))
+				|| (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;