diff --git a/src/p_spec.c b/src/p_spec.c
index c4c254a824d4ec80c37ac78c4d478e6930a7e285..af1a04434033f9c68603d10ccac2a4d719f34a91 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -6232,7 +6232,7 @@ boolean P_CompareSectorPortals(sectorportal_t *a, sectorportal_t *b)
 	}
 }
 
-static mobj_t *GetSectorPortalObject(INT32 tag)
+static mobj_t *P_GetMobjByTag(INT32 tag)
 {
 	for (thinker_t *th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
@@ -6251,6 +6251,27 @@ static mobj_t *GetSectorPortalObject(INT32 tag)
 	return NULL;
 }
 
+static void P_CopySectorPortal(sectorportal_t *dest, sectorportal_t *src)
+{
+	if (src->type == SECPORTAL_NONE)
+		return;
+
+	memcpy(dest, src, sizeof(sectorportal_t));
+}
+
+static void P_DoPortalCopyFromLine(sectorportal_t *floorportal, sectorportal_t *ceilportal, int tag)
+{
+	INT32 secnum = -1;
+	TAG_ITER_SECTORS(tag, secnum)
+	{
+		sector_t *src_sector = &sectors[secnum];
+		if (floorportal)
+			P_CopySectorPortal(floorportal, &src_sector->portal_floor);
+		if (ceilportal)
+			P_CopySectorPortal(ceilportal, &src_sector->portal_ceiling);
+	}
+}
+
 /** After the map has loaded, scans for specials that spawn 3Dfloors and
   * thinkers.
   *
@@ -6496,7 +6517,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 					// Use mobj as viewpoint
 					else if (portal_type == 8)
 					{
-						mobj_t *mobj = GetSectorPortalObject(misc);
+						mobj_t *mobj = P_GetMobjByTag(misc);
 						if (!mobj)
 							break;
 						if (floor)
@@ -7289,10 +7310,6 @@ void P_SpawnSpecials(boolean fromnetsave)
 		}
 	}
 
-
-
-
-
 	// Allocate each list
 	for (i = 0; i < numsectors; i++)
 		if(secthinkers[i].thinkers)
@@ -7321,6 +7338,48 @@ void P_SpawnSpecials(boolean fromnetsave)
 		}
 	}
 
+	// Copy portals
+	for (i = 0; i < numlines; i++)
+	{
+		if (lines[i].special != 6)
+			continue;
+
+		int portal_type = lines[i].args[1];
+		if (portal_type != 1)
+			continue;
+
+		int target_sector_tag = lines[i].args[0];
+		int plane_type = lines[i].args[2];
+		int tag_to_copy = lines[i].args[3];
+
+		boolean floor, ceiling;
+		if (plane_type == TMP_BOTH)
+			floor = ceiling = true;
+		else
+		{
+			floor = plane_type == TMP_FLOOR;
+			ceiling = plane_type == TMP_CEILING;
+		}
+
+		if (target_sector_tag == 0)
+		{
+			sectorportal_t *floorportal = floor ? &lines[i].frontsector->portal_floor : NULL;
+			sectorportal_t *ceilportal = ceiling ? &lines[i].frontsector->portal_ceiling : NULL;
+			P_DoPortalCopyFromLine(floorportal, ceilportal, tag_to_copy);
+		}
+		else
+		{
+			INT32 s1 = -1;
+			TAG_ITER_SECTORS(target_sector_tag, s1)
+			{
+				sectorportal_t *floorportal = floor ? &sectors[s1].portal_floor : NULL;
+				sectorportal_t *ceilportal = ceiling ? &sectors[s1].portal_ceiling : NULL;
+				P_DoPortalCopyFromLine(floorportal, ceilportal, tag_to_copy);
+			}
+		}
+		break;
+	}
+
 	if (!fromnetsave)
 		P_RunLevelLoadExecutors();
 }