diff --git a/src/dehacked.c b/src/dehacked.c
index ae3099c580c9f65e1a56a9dd4105f939169ef26f..b2290e2fff60f73e0e4f31400998580012f1ce27 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -6749,6 +6749,7 @@ static const char *const MOBJFLAG2_LIST[] = {
 	"BOSSFLEE",		// Boss is fleeing!
 	"BOSSDEAD",		// Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
 	"AMBUSH",       // Alternate behaviour typically set by MTF_AMBUSH
+	"LINKDRAW",
 	NULL
 };
 
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 50af8acc90a9b7a0a20cc0240f0c6621a2d78c3a..69e0e11aac036ed2d54f937d03c5e8f0c0acc479 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -192,6 +192,7 @@ typedef enum
 	MF2_BOSSFLEE       = 1<<25, // Boss is fleeing!
 	MF2_BOSSDEAD       = 1<<26, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
 	MF2_AMBUSH         = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH
+	MF2_LINKDRAW       = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
 	// free: to and including 1<<31
 } mobjflag2_t;
 
diff --git a/src/r_things.c b/src/r_things.c
index 13d232d78d0b05d2a48673891b025b68648b7ac2..2360cc23f27207baa35fe9df4d06201ed524d75b 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1119,12 +1119,14 @@ static void R_ProjectSprite(mobj_t *thing)
 
 	vissprite_t *vis;
 
-	angle_t ang = 0;
+	angle_t ang = 0; // compiler complaints
 	fixed_t iscale;
-	fixed_t scalestep; // toast '16
+	fixed_t scalestep;
 	fixed_t offset, offset2;
 	boolean papersprite = (thing->frame & FF_PAPERSPRITE);
 
+	INT32 dispoffset = thing->info->dispoffset;
+
 	//SoM: 3/17/2000
 	fixed_t gz, gzt;
 	INT32 heightsec, phs;
@@ -1312,6 +1314,36 @@ static void R_ProjectSprite(mobj_t *thing)
 
 	xscale = FixedMul(xscale, ang_scale);
 
+	if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY)
+	{
+		mobj_t *link, *link2;
+		fixed_t linkscale;
+
+		for (link = thing->tracer; (link->tracer && (link->flags2 & MF2_LINKDRAW)); link = link->tracer)
+			link->flags2 &= ~MF2_LINKDRAW; // to prevent infinite loops, otherwise would just be a ;
+
+		for (link2 = thing->tracer; (link2->tracer && (link2 != link)); link2 = link2->tracer)
+			link->flags2 |= MF2_LINKDRAW; // only needed for correction of the above
+
+		if (link->flags2 & MF2_LINKDRAW)
+			link->flags2 &= ~MF2_LINKDRAW; // let's try and make sure this doesn't happen again...
+
+		tr_x = link->x - viewx;
+		tr_y = link->y - viewy;
+		gxt = FixedMul(tr_x, viewcos);
+		gyt = -FixedMul(tr_y, viewsin);
+		tz = gxt-gyt;
+		linkscale = FixedDiv(projectiony, tz);
+
+		if (tz < FixedMul(MINZ, this_scale))
+			return;
+
+		if (sortscale < linkscale)
+			dispoffset *= -1; // if it's physically behind, make sure it's ordered behind (if dispoffset > 0)
+
+		sortscale = linkscale; // now make sure it's linked 
+	}
+
 	// PORTAL SPRITE CLIPPING
 	if (portalrender)
 	{
@@ -1394,7 +1426,7 @@ static void R_ProjectSprite(mobj_t *thing)
 	vis->mobjflags = thing->flags;
 	vis->scale = yscale; //<<detailshift;
 	vis->sortscale = sortscale;
-	vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15
+	vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15
 	vis->gx = thing->x;
 	vis->gy = thing->y;
 	vis->gz = gz;
diff --git a/src/r_things.h b/src/r_things.h
index 360ead43382f6dc0f3d785d3c99297b75146345b..01cfc8903e2d29f9852b32bb21878319f001b5f2 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -135,8 +135,8 @@ typedef struct vissprite_s
 	fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors
 
 	fixed_t startfrac; // horizontal position of x1
-	fixed_t scale, sortscale; // sortscale only differs from scale for flat sprites
-	fixed_t scalestep; // only for flat sprites, 0 otherwise
+	fixed_t scale, sortscale; // sortscale only differs from scale for paper sprites and MF2_LINKDRAW
+	fixed_t scalestep; // only for paper sprites, 0 otherwise
 	fixed_t xiscale; // negative if flipped
 
 	fixed_t texturemid;