diff --git a/src/d_player.h b/src/d_player.h
index c133af7039cac5b02ef609be63b8f1fadbc19453..eff8e54f5f1ceed71d24b6fff8190f8b345d4d19 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -234,7 +234,8 @@ typedef enum
 	CR_ZOOMTUBE,
 	CR_ROPEHANG,
 	CR_MACESPIN,
-	CR_MINECART
+	CR_MINECART,
+	CR_PTERABYTE
 } carrytype_t; // pw_carry
 
 // Player powers. (don't edit this comment)
diff --git a/src/dehacked.c b/src/dehacked.c
index b2a0239c66d6fa157b9163a3feb12a2ad192cb38..d19f43f9c03b52b1a2d3672305404901749a9bc2 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -8594,6 +8594,7 @@ struct {
 	{"CR_ROPEHANG",CR_ROPEHANG},
 	{"CR_MACESPIN",CR_MACESPIN},
 	{"CR_MINECART",CR_MINECART},
+	{"CR_PTERABYTE",CR_PTERABYTE},
 
 	// Ring weapons (ringweapons_t)
 	// Useful for A_GiveWeapon
diff --git a/src/p_enemy.c b/src/p_enemy.c
index db76ab4f4ef90a1a5a1fbc8ed406276f9f199c3e..7ad65c1d0af278ee681889b3f425e0077c73bcd8 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -13878,6 +13878,7 @@ void A_SpawnPterabytes(mobj_t *actor)
 		s = FINESINE(fa);
 		waypoint = P_SpawnMobjFromMobj(actor, FixedMul(c, rad), FixedMul(s, rad), 0, MT_PTERABYTEWAYPOINT);
 		waypoint->angle = ang + ANGLE_90;
+		P_SetTarget(&waypoint->tracer, actor);
 		ptera = P_SpawnMobjFromMobj(waypoint, 0, 0, 0, MT_PTERABYTE);
 		ptera->angle = waypoint->angle;
 		P_SetTarget(&ptera->tracer, waypoint);
diff --git a/src/p_inter.c b/src/p_inter.c
index 0030e8e58e5a827ea57efe595680f86e9da9c25d..cbf8153b4b3a9f6d39c1fb2beb08a6f5c95bb4fa 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -456,6 +456,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 
 		if (P_PlayerCanDamage(player, special)) // Do you possess the ability to subdue the object?
 		{
+			if (special->type == MT_PTERABYTE && special->target == player->mo && special->extravalue1 == 1)
+				return; // Can't hurt a Pterabyte if it's trying to pick you up
+
 			if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
 			{
 				if (elementalpierce == 2)
@@ -477,7 +480,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				P_TwinSpinRejuvenate(player, player->thokitem);
 		}
 		else
+		{
+			if (special->type == MT_PTERABYTE && special->target == player->mo)
+				return; // Don't hurt the player you're trying to grab
+
 			P_DamageMobj(toucher, special, special, 1, 0);
+		}
 
 		return;
 	}
diff --git a/src/p_map.c b/src/p_map.c
index cc9209ea8b8e0951a46e091801f39869765c18fd..1455f3a4f056313314df95265895e755e589fe57 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -490,6 +490,40 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
 	}
 }
 
+static void P_DoPterabyteCarry(player_t *player, mobj_t *ptera)
+{
+	if (player->powers[pw_carry])
+		return;
+	if (ptera->extravalue1 != 1)
+		return; // Not swooping
+	if (ptera->target != player->mo)
+		return; // Not swooping for you!
+
+	if (player->spectator)
+		return;
+
+	if ((player->mo->eflags & MFE_VERTICALFLIP) != (ptera->eflags & MFE_VERTICALFLIP))
+		return; // Both should be in same gravity
+
+	if (ptera->eflags & MFE_VERTICALFLIP)
+	{
+		if (ptera->ceilingz - (ptera->z + ptera->height) < player->mo->height - FixedMul(2*FRACUNIT, player->mo->scale))
+			return;
+	}
+	else if (ptera->z - ptera->floorz < player->mo->height - FixedMul(2*FRACUNIT, player->mo->scale))
+		return; // No room to pick up this guy!
+
+	P_ResetPlayer(player);
+	P_SetTarget(&player->mo->tracer, ptera);
+	player->powers[pw_carry] = CR_PTERABYTE;
+	S_StartSound(player->mo, sfx_s3k4a);
+	P_UnsetThingPosition(player->mo);
+	player->mo->x = ptera->x;
+	player->mo->y = ptera->y;
+	P_SetThingPosition(player->mo);
+	ptera->movefactor = 3*TICRATE;
+}
+
 static void P_DoTailsCarry(player_t *sonic, player_t *tails)
 {
 	INT32 p;
@@ -920,6 +954,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
 			P_DamageMobj(thing, tmthing, tmthing, 1, 0);
 	}
 
+	if (thing->type == MT_PTERABYTE && tmthing->player)
+		P_DoPterabyteCarry(tmthing->player, thing);
+
 	if (thing->type == MT_VULTURE && tmthing->type == MT_VULTURE)
 	{
 		fixed_t dx = thing->x - tmthing->x;
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 4258ac40232edabf6ee21a3a3897f604acb9aa7c..4388c1bd6ea8fb5e86419aa53e794751154d6d66 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -9078,7 +9078,18 @@ void P_MobjThinker(mobj_t *mobj)
 				}
 			case MT_PTERABYTE:
 				{
-					if (mobj->extravalue1 == 0) // Hovering
+					if (mobj->extravalue1 & 4) // Cooldown after grabbing
+					{
+						if (mobj->movefactor)
+							mobj->movefactor--;
+						else
+						{
+							P_SetTarget(&mobj->target, NULL);
+							mobj->extravalue1 &= 3;
+						}
+					}
+
+					if ((mobj->extravalue1 & 3) == 0) // Hovering
 					{
 						fixed_t vdist, hdist, time;
 						fixed_t hspeed = 3*mobj->info->speed;
@@ -9087,21 +9098,31 @@ void P_MobjThinker(mobj_t *mobj)
 						var1 = 1;
 						var2 = 0;
 						A_CapeChase(mobj);
+
+						if (mobj->target)
+							break; // Still carrying a player or in cooldown
+
 						P_LookForPlayers(mobj, true, false, 256*FRACUNIT);
 
 						if (!mobj->target)
 							break;
 
-						vdist = mobj->z - mobj->target->z;
+						vdist = mobj->z - mobj->target->z - mobj->target->height;
 						if (vdist <= 0)
+						{
+							P_SetTarget(&mobj->target, NULL);
 							break;
+						}
 
 						hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
 						if (hdist > 450*FRACUNIT)
+						{
+							P_SetTarget(&mobj->target, NULL);
 							break;
+						}
 
 						P_SetMobjState(mobj, S_PTERABYTE_SWOOPDOWN);
-						mobj->extravalue1 = 1;
+						mobj->extravalue1++;
 						S_StartSound(mobj, mobj->info->attacksound);
 						time = FixedDiv(hdist, hspeed);
 						mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
@@ -9113,7 +9134,7 @@ void P_MobjThinker(mobj_t *mobj)
 						mobj->movecount = time >> FRACBITS;
 						mobj->reactiontime = mobj->movecount;
 					}
-					else if (mobj->extravalue1 == 1) // Swooping
+					else if ((mobj->extravalue1 & 3) == 1) // Swooping
 					{
 						mobj->reactiontime--;
 						mobj->momz += mobj->extravalue2;
@@ -9128,8 +9149,9 @@ void P_MobjThinker(mobj_t *mobj)
 						else if (mobj->state - states == S_PTERABYTE_SWOOPUP)
 						{
 							P_SetMobjState(mobj, S_PTERABYTE_FLY1);
-							mobj->extravalue1 = 2;
-							P_SetTarget(&mobj->target, NULL);
+							mobj->extravalue1++;
+							if (mobj->target && mobj->target->tracer != mobj)
+								P_SetTarget(&mobj->target, NULL); // Failed to grab the target
 							mobj->momx = mobj->momy = mobj->momz = 0;
 						}
 					}
@@ -9140,7 +9162,7 @@ void P_MobjThinker(mobj_t *mobj)
 						A_HomingChase(mobj);
 						if (P_AproxDistance(mobj->x - mobj->tracer->x, mobj->y - mobj->tracer->y) <= mobj->info->speed)
 						{
-							mobj->extravalue1 = 0;
+							mobj->extravalue1 -= 2;
 							mobj->momx = mobj->momy = mobj->momz = 0;
 						}
 					}
diff --git a/src/p_user.c b/src/p_user.c
index 1ca955e496c55683cbc0e3ecbb42ec2b0e15f242..4895095f2ee69110588e6c085d1fb31d7e1842eb 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -4279,6 +4279,9 @@ void P_DoJump(player_t *player, boolean soundandstate)
 		if (player->mo->ceilingz-player->mo->floorz <= player->mo->height-1)
 			return;
 
+		if (player->powers[pw_carry] == CR_PTERABYTE)
+			return;
+
 		// Jump this high.
 		if (player->powers[pw_carry] == CR_PLAYER)
 		{
@@ -11518,6 +11521,36 @@ void P_PlayerThink(player_t *player)
 	}*/
 }
 
+// Checks if the mobj is above lava. Used by Pterabyte.
+static boolean P_MobjAboveLava(mobj_t *mobj)
+{
+	sector_t *sector = mobj->subsector->sector;
+
+	if (sector->ffloors)
+	{
+		ffloor_t *rover;
+
+		for (rover = sector->ffloors; rover; rover = rover->next)
+		{
+			if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || GETSECSPECIAL(rover->master->frontsector->special, 1) != 3)
+				continue;
+
+			if (mobj->eflags & MFE_VERTICALFLIP)
+			{
+				if (*rover->bottomheight <= mobj->ceilingz && *rover->bottomheight >= mobj->z)
+					return true;
+			}
+			else
+			{
+				if (*rover->topheight >= mobj->floorz && *rover->topheight <= mobj->z)
+					return true;
+			}
+		}
+	}
+
+	return false;
+}
+
 //
 // P_PlayerAfterThink
 //
@@ -11831,6 +11864,60 @@ void P_PlayerAfterThink(player_t *player)
 				}
 				break;
 			}
+			case CR_PTERABYTE: // being carried by a Pterabyte
+			{
+				mobj_t *ptera = player->mo->tracer;
+				mobj_t *spawnpoint = ptera->tracer->tracer;
+				player->mo->height = FixedDiv(P_GetPlayerHeight(player), FixedDiv(14 * FRACUNIT, 10 * FRACUNIT));
+
+				if (ptera->health <= 0)
+					goto dropoff;
+
+				if (P_MobjAboveLava(ptera))
+					goto dropoff;
+
+				if (player->mo->eflags & MFE_VERTICALFLIP)
+				{
+					if ((ptera->z + ptera->height + player->mo->height + FixedMul(FRACUNIT, player->mo->scale)) <= ptera->ceilingz
+						&& (ptera->eflags & MFE_VERTICALFLIP)) // Reverse gravity check for the carrier - Flame
+						player->mo->z = ptera->z + ptera->height + FixedMul(FRACUNIT, player->mo->scale);
+
+					if (ptera->ceilingz - ptera->z > spawnpoint->ceilingz - spawnpoint->z + 512*FRACUNIT)
+						goto dropoff;
+				}
+				else
+				{
+					if ((ptera->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale)) >= ptera->floorz
+						&& !(ptera->eflags & MFE_VERTICALFLIP)) // Correct gravity check for the carrier - Flame
+						player->mo->z = ptera->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale);
+
+					if (ptera->z - ptera->floorz > spawnpoint->z - spawnpoint->floorz + 512 * FRACUNIT)
+						goto dropoff;
+				}
+
+				ptera->movefactor--;
+				if (!ptera->movefactor)
+					goto dropoff;
+
+				P_TryMove(player->mo, ptera->x, ptera->y, true);
+				player->mo->momx = ptera->momx;
+				player->mo->momy = ptera->momy;
+				player->mo->momz = ptera->momz;
+
+				if (P_AproxDistance(player->mo->x - ptera->x, player->mo->y - ptera->y) > player->mo->radius)
+					goto dropoff;
+
+				if (player->mo->state-states != S_PLAY_RIDE)
+					P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
+				break;
+
+			dropoff:
+				player->powers[pw_carry] = CR_NONE;
+				P_SetTarget(&player->mo->tracer, NULL);
+				ptera->movefactor = TICRATE;
+				ptera->extravalue1 |= 4;
+				break;
+			}
 			default:
 				break;
 		}