diff --git a/src/dehacked.c b/src/dehacked.c
index c172549e1bcf2a7d12965d9cdace291136ab01d8..ced71f079eb35f2a160a5e371f89a15a59218b9f 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -6515,7 +6515,6 @@ static const char *const MOBJFLAG2_LIST[] = {
 	"AMBUSH",         // Alternate behaviour typically set by MTF_AMBUSH
 	"LINKDRAW",       // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
 	"SHIELD",         // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use)
-	"MACEROTATE",     // Thinker calls P_MaceRotate around tracer
 	NULL
 };
 
diff --git a/src/info.c b/src/info.c
index acb12379a9e021c93fa07155ab668b1592dc075b..f11d88af81a2c3663c1b17b226bb6fc4c4e42636 100644
--- a/src/info.c
+++ b/src/info.c
@@ -9011,7 +9011,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		10000,          // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
@@ -9038,7 +9038,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		10000,          // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
@@ -9065,7 +9065,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		10000,          // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
@@ -9092,7 +9092,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		10000,          // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
@@ -9119,7 +9119,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		0,              // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
+		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
@@ -9146,7 +9146,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		200,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
@@ -9173,7 +9173,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		200,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 9d65a583207055b35349dc64854888d845d9013b..4040e271df038bb9ae3014c0ea0d49eaa89741ca 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -776,6 +776,19 @@ static int lib_pCanRunOnWater(lua_State *L)
 	return 1;
 }
 
+static int lib_pMaceRotate(lua_State *L)
+{
+	mobj_t *center = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	INT32 baserot = luaL_checkinteger(L, 2);
+	INT32 baseprevrot = luaL_checkinteger(L, 3);
+	NOHUD
+	INLEVEL
+	if (!center)
+		return LUA_ErrInvalid(L, "mobj_t");
+	P_MaceRotate(center, baserot, baseprevrot);
+	return 0;
+}
+
 // P_USER
 ////////////
 
@@ -2526,6 +2539,7 @@ static luaL_Reg lib[] = {
 	{"P_CheckDeathPitCollide",lib_pCheckDeathPitCollide},
 	{"P_CheckSolidLava",lib_pCheckSolidLava},
 	{"P_CanRunOnWater",lib_pCanRunOnWater},
+	{"P_MaceRotate",lib_pMaceRotate},
 
 	// p_user
 	{"P_GetPlayerHeight",lib_pGetPlayerHeight},
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index d384b75d1b5163e7f24ffb83a3177f0e84585fd4..1583bd3c4df9f335338f5d56d7e04dc5997a6f1e 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -530,10 +530,22 @@ static int mobj_set(lua_State *L)
 	case mobj_bprev:
 		return UNIMPLEMENTED;
 	case mobj_hnext:
-		mo->hnext = luaL_checkudata(L, 3, META_MOBJ);
+		if (lua_isnil(L, 3))
+			P_SetTarget(&mo->hnext, NULL);
+		else
+		{
+			mobj_t *hnext = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
+			P_SetTarget(&mo->hnext, hnext);
+		}
 		break;
 	case mobj_hprev:
-		mo->hprev = luaL_checkudata(L, 3, META_MOBJ);
+		if (lua_isnil(L, 3))
+			P_SetTarget(&mo->hprev, NULL);
+		else
+		{
+			mobj_t *hprev = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
+			P_SetTarget(&mo->hprev, hprev);
+		}
 		break;
 	case mobj_type: // yeah sure, we'll let you change the mobj's type.
 	{
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 9acc8430ec991881b102a173d4f08d3edd05f82f..a8ce7869c5b0ab5ddd9cd815a2e61076655268f2 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -4917,6 +4917,7 @@ void A_SlingAppear(mobj_t *actor)
 	boolean firsttime = true;
 	UINT8 mlength = 4;
 	mobj_t *spawnee;
+	mobj_t *hprev = actor;
 #ifdef HAVE_BLUA
 	if (LUA_CallAction("A_SlingAppear", actor))
 		return;
@@ -4927,7 +4928,6 @@ void A_SlingAppear(mobj_t *actor)
 	P_SetThingPosition(actor);
 	actor->lastlook = 128;
 	actor->movecount = actor->lastlook;
-	actor->health = actor->angle>>ANGLETOFINESHIFT;
 	actor->threshold = 0;
 	actor->movefactor = actor->threshold;
 	actor->friction = 128;
@@ -4936,10 +4936,13 @@ void A_SlingAppear(mobj_t *actor)
 	{
 		spawnee = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMALLMACECHAIN);
 
-		P_SetTarget(&spawnee->target, actor);
+		P_SetTarget(&spawnee->tracer, actor);
+		P_SetTarget(&spawnee->hprev, hprev);
+		P_SetTarget(&hprev->hnext, spawnee);
+		hprev = spawnee;
 
-		spawnee->threshold = 0;
-		spawnee->reactiontime = mlength;
+		spawnee->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT;
+		spawnee->movecount = mlength;
 
 		if (firsttime)
 		{
diff --git a/src/p_local.h b/src/p_local.h
index 54ae37ed24d241f8ddf17ab00377211a562ff61e..49d3ed614793431cd473caab570636c53c973b64 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -280,6 +280,8 @@ mobj_t *P_GetClosestAxis(mobj_t *source);
 
 boolean P_CanRunOnWater(player_t *player, ffloor_t *rover);
 
+void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot);
+
 void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration);
 #define PAL_WHITE    1
 #define PAL_MIXUP    2
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 8695d57e4098898e48a24530f718818e861b2bb8..2e78c098eb827a55e4eaeda8ced99f273d7be0b4 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -6176,98 +6176,149 @@ static void P_NightsItemChase(mobj_t *thing)
 
 //
 // P_MaceRotate
-// Spins an object around its target, or, swings it from side to side.
+// Spins a hnext-chain of objects around its centerpoint, side to side or periodically.
 //
-static void P_MaceRotate(mobj_t *mobj)
+void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot)
 {
-	TVector v;
+	TVector unit, baseuo, unitoffset;
 	TVector *res;
-	fixed_t radius, dist;
+	fixed_t radius, dist, wah;
 	angle_t fa;
-	INT32 prevswing;
-	boolean donetwice = false;
+	//boolean donetwice = false;
+	boolean dosound = false;
+	mobj_t *mobj = center->hnext, *hnext = NULL;
 
 	// Tracer was removed.
-	if (!mobj->health)
+	/*if (!mobj->health)
 		return;
 	else if (!mobj->tracer)
 	{
 		P_KillMobj(mobj, NULL, NULL, 0);
 		return;
-	}
+	}*/
 
-	mobj->momx = mobj->momy = mobj->momz = 0;
+	INT32 rot = (baserot &= FINEMASK);
+	INT32 prevrot = (baseprevrot &= FINEMASK);
 
-	prevswing = mobj->threshold;
-	mobj->threshold += mobj->tracer->lastlook;
-	mobj->threshold &= FINEMASK;
+	INT32 lastthreshold = FINEMASK; // needs to never be equal at start of loop
+	fixed_t lastfriction = INT32_MIN; // ditto; almost certainly never, but...
 
-	dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed);
+	fixed_t movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = 0;
 
-	// Radius of the link's rotation.
-	radius = FixedMul(dist * mobj->movecount, mobj->tracer->scale) + mobj->tracer->extravalue1;
+	baseuo[3] = 0;
 
-maceretry:
+	while (mobj)
+	{
+		mobj->momx = mobj->momy = mobj->momz = 0;
 
-	fa = (FixedAngle(mobj->tracer->movefactor*FRACUNIT) >> ANGLETOFINESHIFT);
-	radius = FixedMul(FINECOSINE(fa), radius);
-	v[1] = -FixedMul(FINESINE(fa), radius)
-	+ FixedMul(dist * mobj->movefactor, mobj->tracer->scale);
-	v[3] = FRACUNIT;
+		if (mobj->threshold != lastthreshold
+		|| mobj->friction != lastfriction)
+		{
+			rot = (baserot + mobj->threshold) & FINEMASK;
+			prevrot = (baseprevrot + mobj->threshold) & FINEMASK;
 
-	// Swinging Chain.
-	if (mobj->tracer->flags2 & MF2_STRONGBOX)
-	{
-		fixed_t swingmagnitude = FixedMul(FINECOSINE(mobj->threshold), mobj->tracer->lastlook << FRACBITS);
-		prevswing = FINECOSINE(prevswing);
+			fa = (FixedAngle(center->movefactor*FRACUNIT) >> ANGLETOFINESHIFT); // mpinch
+			radius = FINECOSINE(fa);
+			unit[1] = -FixedMul(FINESINE(fa), radius);
+			unit[3] = center->scale;
 
-		if (!donetwice
-		&& (mobj->flags2 & MF2_BOSSNOTRAP) // at the end of the chain and can play a sound
-		&& ((prevswing > 0) != (swingmagnitude > 0))) // just passed its lowest point
-			S_StartSound(mobj, mobj->info->activesound);
+			// Swinging Chain.
+			if (center->flags2 & MF2_STRONGBOX)
+			{
+				fixed_t swingmag = FixedMul(FINECOSINE(rot), center->lastlook << FRACBITS);
+				fixed_t prevswingmag = FINECOSINE(prevrot);
 
-		fa = ((FixedAngle(swingmagnitude) >> ANGLETOFINESHIFT) + mobj->friction) & FINEMASK;
+				if ((prevswingmag > 0) != (swingmag > 0)) // just passed its lowest point
+					dosound = true;
+					//S_StartSound(mobj, mobj->info->activesound);
 
-		v[0] = FixedMul(FINESINE(fa), -radius);
-		v[2] = FixedMul(FINECOSINE(fa), -radius);
-	}
-	// Rotating Chain.
-	else
-	{
-		prevswing = (prevswing + mobj->friction) & FINEMASK;
-		fa = (mobj->threshold + mobj->friction) & FINEMASK;
+				fa = ((FixedAngle(swingmag) >> ANGLETOFINESHIFT) + mobj->friction) & FINEMASK;
 
-		if (!donetwice
-		&& (mobj->flags2 & MF2_BOSSNOTRAP) // at the end of the chain and can play a sound
-		&& (!(prevswing > (FINEMASK/2)) && (fa > (FINEMASK/2)))) // completed a full swing
+				unit[0] = FixedMul(FINESINE(fa), -radius);
+				unit[2] = FixedMul(FINECOSINE(fa), -radius);
+			}
+			// Rotating Chain.
+			else
+			{
+				angle_t prevfa = (prevrot + mobj->friction) & FINEMASK;
+				fa = (rot + mobj->friction) & FINEMASK;
+
+				if (!(prevfa > (FINEMASK/2)) && (fa > (FINEMASK/2))) // completed a full swing
+					dosound = true;
+
+				unit[0] = FixedMul(FINECOSINE(fa), radius);
+				unit[2] = FixedMul(FINESINE(fa), radius);
+			}
+
+			// Calculate the angle matrixes for the link.
+			res = VectorMatrixMultiply(unit, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT));
+			M_Memcpy(&unit, res, sizeof(unit));
+			res = VectorMatrixMultiply(unit, *RotateZMatrix(center->angle));
+			M_Memcpy(&unit, res, sizeof(unit));
+		}
+
+		if (dosound && (mobj->flags2 & MF2_BOSSNOTRAP))
+		{
 			S_StartSound(mobj, mobj->info->activesound);
+			dosound = false;
+		}
 
-		v[0] = FixedMul(FINECOSINE(fa), radius);
-		v[2] = FixedMul(FINESINE(fa), radius);
-	}
+		dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed);
 
-	// Calculate the angle matrixes for the link.
-	res = VectorMatrixMultiply(v, *RotateXMatrix(mobj->tracer->threshold << ANGLETOFINESHIFT));
-	M_Memcpy(&v, res, sizeof(v));
-	res = VectorMatrixMultiply(v, *RotateZMatrix(mobj->tracer->health << ANGLETOFINESHIFT));
-	M_Memcpy(&v, res, sizeof(v));
+		if (dist*mobj->movefactor != movefac)
+		{
+			if (!baseuo[3])
+			{
+				baseuo[1] = FRACUNIT;
+				baseuo[3] = center->scale;
+				baseuo[0] = baseuo[2] = 0;
 
-	// Cut the height to align the link with the axis.
-	if (mobj->type == MT_SMALLMACECHAIN || mobj->type == MT_BIGMACECHAIN)
-		v[2] -= P_MobjFlip(mobj)*mobj->height/4;
-	else
-		v[2] -= P_MobjFlip(mobj)*mobj->height/2;
+				res = VectorMatrixMultiply(baseuo, *RotateXMatrix(center->threshold << ANGLETOFINESHIFT));
+				M_Memcpy(&baseuo, res, sizeof(unit));
+				res = VectorMatrixMultiply(baseuo, *RotateZMatrix(center->angle));
+				M_Memcpy(&baseuo, res, sizeof(unit));
 
-	P_UnsetThingPosition(mobj);
+				lastthreshold = mobj->threshold;
+				lastfriction = mobj->friction;
+			}
+
+			if (mobj->movefactor)
+			{
+				movefac = dist*mobj->movefactor;
+				unitoffset[0] = FixedMul(movefac, baseuo[0]);
+				unitoffset[1] = FixedMul(movefac, baseuo[1]);
+				unitoffset[2] = FixedMul(movefac, baseuo[2]);
+			}
+			else
+				movefac = unitoffset[0] = unitoffset[1] = unitoffset[2] = 0;
+		}
 
-	// Add on the appropriate distances to the center's co-ordinates.
-	mobj->x = mobj->tracer->x + v[0];
-	mobj->y = mobj->tracer->y + v[1];
-	mobj->z = mobj->tracer->z + v[2];
+	//maceretry:
 
-	P_SetThingPosition(mobj);
+		hnext = mobj->hnext; // just in case the mobj is removed
+
+		P_UnsetThingPosition(mobj);
+
+		// Radius of the link's rotation.
+		wah = (dist * mobj->movecount) + center->extravalue1;
+
+		// Add on the appropriate distances to the center's co-ordinates.
+		mobj->x = center->x + FixedMul(unit[0], wah) + unitoffset[0];
+		mobj->y = center->y + FixedMul(unit[1], wah) + unitoffset[1];
+		mobj->z = center->z + FixedMul(unit[2], wah) + unitoffset[2];
+
+		// Cut the height to align the link with the axis.
+		if (mobj->type == MT_SMALLMACECHAIN || mobj->type == MT_BIGMACECHAIN)
+			mobj->z -= P_MobjFlip(mobj)*mobj->height/4;
+		else
+			mobj->z -= P_MobjFlip(mobj)*mobj->height/2;
 
-	if (donetwice || P_MobjWasRemoved(mobj))
+		P_SetThingPosition(mobj);
+
+		mobj = hnext;
+	}
+
+	/*if (donetwice || P_MobjWasRemoved(mobj))
 		return;
 
 	if (mobj->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT))
@@ -6293,7 +6344,7 @@ maceretry:
 	radius = FixedMul(radius, dist);
 	donetwice = true;
 	dist = ((mobj->info->speed) ? mobj->info->speed : mobjinfo[MT_SMALLMACECHAIN].speed);
-	goto maceretry;
+	goto maceretry;*/
 }
 
 static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
@@ -6664,13 +6715,6 @@ void P_MobjThinker(mobj_t *mobj)
 		}
 	}
 
-	if (mobj->flags2 & MF2_MACEROTATE)
-	{
-		P_MaceRotate(mobj);
-		if (P_MobjWasRemoved(mobj))
-			return;
-	}
-
 	// Special thinker for scenery objects
 	if (mobj->flags & MF_SCENERY)
 	{
@@ -6687,6 +6731,29 @@ void P_MobjThinker(mobj_t *mobj)
 
 		switch (mobj->type)
 		{
+			case MT_CHAINPOINT:
+			case MT_CHAINMACEPOINT:
+				if (leveltime & 1)
+				{
+					if (mobj->lastlook > mobj->movecount)
+						mobj->lastlook--;
+	/*
+					if (mobj->threshold > mobj->movefactor)
+						mobj->threshold -= FRACUNIT;
+					else if (mobj->threshold < mobj->movefactor)
+						mobj->threshold += FRACUNIT;*/
+				}
+				/* FALLTHRU */
+			case MT_MACEPOINT:
+			case MT_SPRINGBALLPOINT:
+			case MT_FIREBARPOINT:
+			case MT_CUSTOMMACEPOINT:
+			case MT_HIDDEN_SLING:
+				// The following was pretty good, but liked breaking whenever mobj->lastlook changed.
+				//P_MaceRotate(mobj, ((leveltime + 1) * mobj->lastlook), (leveltime * mobj->lastlook));
+				P_MaceRotate(mobj, mobj->movedir + mobj->lastlook, mobj->movedir);
+				mobj->movedir = (mobj->movedir + mobj->lastlook) & FINEMASK;
+				break;
 			case MT_HOOP:
 				if (mobj->fuse > 1)
 					P_MoveHoop(mobj);
@@ -7337,19 +7404,6 @@ void P_MobjThinker(mobj_t *mobj)
 				}
 			}
 			break;
-		case MT_CHAINPOINT:
-		case MT_CHAINMACEPOINT:
-			if (leveltime & 1)
-			{
-				if (mobj->lastlook > mobj->movecount)
-					mobj->lastlook--;
-/*
-				if (mobj->threshold > mobj->movefactor)
-					mobj->threshold -= FRACUNIT;
-				else if (mobj->threshold < mobj->movefactor)
-					mobj->threshold += FRACUNIT;*/
-			}
-			break;
 		case MT_EGGCAPSULE:
 			if (!mobj->reactiontime)
 			{
@@ -8615,6 +8669,13 @@ void P_RemoveMobj(mobj_t *mobj)
 	// Remove any references to other mobjs.
 	P_SetTarget(&mobj->target, P_SetTarget(&mobj->tracer, NULL));
 
+	if (mobj->hnext)
+		P_SetTarget(&mobj->hnext->hprev, mobj->hprev);
+	if (mobj->hprev)
+		P_SetTarget(&mobj->hprev->hnext, mobj->hnext);
+
+	P_SetTarget(&mobj->hnext, P_SetTarget(&mobj->hprev, NULL));
+
 	// free block
 	// DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error.
 	if (mobj->flags & MF_NOTHINK && !mobj->thinker.next)
@@ -9301,6 +9362,7 @@ void P_SpawnMapThing(mapthing_t *mthing)
 	mobj_t *mobj;
 	fixed_t x, y, z;
 	subsector_t *ss;
+	boolean doangle = true;
 
 	if (!mthing->type)
 		return; // Ignore type-0 things as NOPs
@@ -9710,7 +9772,7 @@ void P_SpawnMapThing(mapthing_t *mthing)
 		angle_t mspokeangle;
 		mobjtype_t chainlink, macetype, firsttype, linktype;
 		boolean mdoall = true;
-		mobj_t *spawnee;
+		mobj_t *spawnee, *hprev;
 		mobjflag_t mflagsapply;
 		mobjflag2_t mflags2apply;
 		mobjeflag_t meflagsapply;
@@ -9748,7 +9810,7 @@ ML_EFFECT4 : Don't clip inside the ground
 		mspeed = abs(lines[line].dy >> (FRACBITS - 4));
 		mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360;
 		if ((mmaxspeed = sides[lines[line].sidenum[0]].rowoffset >> (FRACBITS - 4)) < mspeed)
-			mmaxspeed = mspeed << 1;
+			mmaxspeed = mspeed;
 		mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360;
 		myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360;
 
@@ -9787,10 +9849,12 @@ ML_EFFECT4 : Don't clip inside the ground
 
 		mobj->lastlook = mspeed;
 		mobj->movecount = mobj->lastlook;
-		mobj->health = (FixedAngle(myaw*FRACUNIT)>>ANGLETOFINESHIFT);
+		mobj->angle = FixedAngle(myaw*FRACUNIT);
+		doangle = false;
 		mobj->threshold = (FixedAngle(mpitch*FRACUNIT)>>ANGLETOFINESHIFT);
 		mobj->friction = mmaxspeed;
 		mobj->movefactor = mpinch;
+		mobj->movedir = 0;
 
 		// Mobjtype selection
 		switch(mobj->type)
@@ -9857,7 +9921,7 @@ ML_EFFECT4 : Don't clip inside the ground
 			mmin = mnumspokes;
 
 		// Make the links the same type as the end - repeated below
-		if ((mobj->type != MT_CHAINPOINT) && ((lines[line].flags & ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or
+		if ((mobj->type != MT_CHAINPOINT) && (((lines[line].flags & ML_EFFECT2) == ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or
 		{
 			linktype = macetype;
 			radiusfactor = 2; // Double the radius.
@@ -9866,7 +9930,7 @@ ML_EFFECT4 : Don't clip inside the ground
 			radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1);
 
 		mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP|MF_NOCLIPHEIGHT));
-		mflags2apply = (MF2_MACEROTATE|((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0));
+		mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0);
 		meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0);
 
 		msound = ((firsttype == chainlink) ? 0 : (mwidth & 1));
@@ -9875,6 +9939,8 @@ ML_EFFECT4 : Don't clip inside the ground
 		mphase = (FixedAngle(mphase*FRACUNIT)>>ANGLETOFINESHIFT);
 		mroll = (FixedAngle(mroll*FRACUNIT)>>ANGLETOFINESHIFT);
 
+		hprev = mobj;
+
 #define makemace(mobjtype, dist, moreflags2) P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\
 				P_SetTarget(&spawnee->tracer, mobj);\
 				spawnee->threshold = mphase;\
@@ -9884,7 +9950,10 @@ ML_EFFECT4 : Don't clip inside the ground
 				spawnee->angle = myaw;\
 				spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\
 				spawnee->flags2 |= (mflags2apply|moreflags2);\
-				spawnee->eflags |= meflagsapply
+				spawnee->eflags |= meflagsapply;\
+				P_SetTarget(&hprev->hnext, spawnee);\
+				P_SetTarget(&spawnee->hprev, hprev);\
+				hprev = spawnee
 
 domaceagain:
 		mnumspokesset = mnumspokes;
@@ -10264,7 +10333,8 @@ domaceagain:
 		}
 	}
 
-	mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
+	if (doangle)
+		mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
 
 	if ((mthing->options & MTF_AMBUSH)
 	&& (mthing->options & MTF_OBJECTSPECIAL)
diff --git a/src/p_mobj.h b/src/p_mobj.h
index c6e1bfbf2317b3f6a4f2f83f42fe04f9e63102fb..ec25855d88b7ff7671c5ab4de3b40ce825264fc3 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -194,8 +194,6 @@ typedef enum
 	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)
 	MF2_SHIELD         = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use)
-	MF2_MACEROTATE     = 1<<30, // Thinker calls P_MaceRotate around tracer
-	// free: to and including 1<<31
 } mobjflag2_t;
 
 typedef enum