diff --git a/src/b_bot.c b/src/b_bot.c
index c8228e840f751b676a00e920cde61dcb8f06311c..af57d65ecf6e3c24e725ed38b9533b9ab6509763 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -589,8 +589,9 @@ void B_RespawnBot(INT32 playernum)
 	}
 	else
 		P_SetMobjState(tails, S_PLAY_FALL);
-	P_SetScale(tails, sonic->scale);
+	P_SetScale(tails, sonic->scale, false);
 	tails->destscale = sonic->destscale;
+	tails->old_scale = sonic->old_scale;
 }
 
 void B_HandleFlightIndicator(player_t *player)
diff --git a/src/g_demo.c b/src/g_demo.c
index 859ac5cba25b2215875e19bdea586160a6989e28..05ee577884ae82c160857142165d29fb236b39f5 100644
--- a/src/g_demo.c
+++ b/src/g_demo.c
@@ -771,7 +771,7 @@ void G_GhostTicker(void)
 			{
 				g->mo->destscale = READFIXED(g->p);
 				if (g->mo->destscale != g->mo->scale)
-					P_SetScale(g->mo, g->mo->destscale);
+					P_SetScale(g->mo, g->mo->destscale, false);
 			}
 			if (xziptic & EZT_THOKMASK)
 			{ // Let's only spawn ONE of these per frame, thanks.
@@ -810,7 +810,7 @@ void G_GhostTicker(void)
 							mobj->frame = (states[mobjinfo[type].spawnstate].frame & FF_FRAMEMASK) | tr_trans60<<FF_TRANSSHIFT;
 							mobj->color = g->mo->color;
 							mobj->skin = g->mo->skin;
-							P_SetScale(mobj, (mobj->destscale = g->mo->scale));
+							P_SetScale(mobj, g->mo->scale, true);
 
 							if (type == MT_THOK) // spintrail-specific modification for MT_THOK
 							{
@@ -926,7 +926,7 @@ void G_GhostTicker(void)
 				else
 					follow->destscale = g->mo->destscale;
 				if (follow->destscale != follow->scale)
-					P_SetScale(follow, follow->destscale);
+					P_SetScale(follow, follow->destscale, false);
 
 				P_UnsetThingPosition(follow);
 				temp = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
@@ -1079,7 +1079,7 @@ void G_ReadMetalTic(mobj_t *metal)
 		{
 			metal->destscale = READFIXED(metal_p);
 			if (metal->destscale != metal->scale)
-				P_SetScale(metal, metal->destscale);
+				P_SetScale(metal, metal->destscale, false);
 		}
 		if (xziptic & EZT_THOKMASK)
 		{ // Let's only spawn ONE of these per frame, thanks.
@@ -1117,7 +1117,7 @@ void G_ReadMetalTic(mobj_t *metal)
 						mobj->angle = metal->angle;
 						mobj->color = metal->color;
 						mobj->skin = metal->skin;
-						P_SetScale(mobj, (mobj->destscale = metal->scale));
+						P_SetScale(mobj, metal->scale, true);
 
 						if (type == MT_THOK) // spintrail-specific modification for MT_THOK
 						{
@@ -1184,7 +1184,7 @@ void G_ReadMetalTic(mobj_t *metal)
 				else
 					follow->destscale = metal->destscale;
 				if (follow->destscale != follow->scale)
-					P_SetScale(follow, follow->destscale);
+					P_SetScale(follow, follow->destscale, false);
 
 				P_UnsetThingPosition(follow);
 				temp = (metalversion < 0x000e) ? READINT16(metal_p)<<8 : READFIXED(metal_p);
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 680c6a2c3ca9afbd48fdf7320d1b8a9e502373fb..2a924e5487a6219dfc37ce0a11bc3d554e5dcb83 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -924,13 +924,14 @@ static int lib_pSetScale(lua_State *L)
 {
 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
 	fixed_t newscale = luaL_checkfixed(L, 2);
+	boolean instant = lua_optboolean(L, 3);
 	NOHUD
 	INLEVEL
 	if (!mobj)
 		return LUA_ErrInvalid(L, "mobj_t");
 	if (newscale < FRACUNIT/100)
 		newscale = FRACUNIT/100;
-	P_SetScale(mobj, newscale);
+	P_SetScale(mobj, newscale, instant);
 	return 0;
 }
 
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 7fd16b32b2c0806f06d2f557823aeabbc5bb4c76..62b02ff3f679a50c7bd09df2807b8d11f5056276 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -762,7 +762,7 @@ static int mobj_set(lua_State *L)
 			return luaL_error(L, "mobj.type %d out of range (0 - %d).", newtype, NUMMOBJTYPES-1);
 		mo->type = newtype;
 		mo->info = &mobjinfo[newtype];
-		P_SetScale(mo, mo->scale);
+		P_SetScale(mo, mo->scale, false);
 		break;
 	}
 	case mobj_info:
@@ -836,9 +836,7 @@ static int mobj_set(lua_State *L)
 		fixed_t scale = luaL_checkfixed(L, 3);
 		if (scale < FRACUNIT/100)
 			scale = FRACUNIT/100;
-		mo->destscale = scale;
-		P_SetScale(mo, scale);
-		mo->old_scale = scale;
+		P_SetScale(mo, scale, true);
 		break;
 	}
 	case mobj_destscale:
diff --git a/src/p_enemy.c b/src/p_enemy.c
index accc700730d6281dea492cb4068704c7561c5239..428c023ff3e6333b7f62cda4e3f528762b1d606e 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -1222,8 +1222,7 @@ static void P_FaceStabFlume(mobj_t *actor)
 	if (P_MobjWasRemoved(flume))
 		return;
 
-	flume->destscale = actor->scale*3;
-	P_SetScale(flume, flume->destscale);
+	P_SetScale(flume, 3*actor->scale, true);
 	P_SetTarget(&flume->target, actor);
 	flume->sprite = SPR_JETF;
 	flume->frame = FF_FULLBRIGHT;
@@ -1342,8 +1341,7 @@ void A_FaceStabHurl(mobj_t *actor)
 					{
 						hwork = hwork->hnext;
 						hwork->angle = actor->angle + ANGLE_90;
-						hwork->destscale = FixedSqrt(step*basesize);
-						P_SetScale(hwork, hwork->destscale);
+						P_SetScale(hwork, FixedSqrt(step*basesize), true);
 						hwork->fuse = 2;
 						P_MoveOrigin(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<<FRACBITS)));
 						if (P_MobjWasRemoved(hwork))
@@ -2486,7 +2484,7 @@ void A_VultureBlast(mobj_t *actor)
 		if (P_MobjWasRemoved(dust))
 			continue;
 
-		P_SetScale(dust, 4*FRACUNIT);
+		P_SetScale(dust, 4*FRACUNIT, true);
 		dust->destscale = FRACUNIT;
 		dust->scalespeed = 4*FRACUNIT/TICRATE;
 		dust->fuse = TICRATE;
@@ -2556,7 +2554,7 @@ void A_VultureFly(mobj_t *actor)
 	dust = P_SpawnMobj(actor->x + P_RandomFixed() - FRACUNIT/2, actor->y + P_RandomFixed() - FRACUNIT/2, actor->z + actor->height/2 + P_RandomFixed() - FRACUNIT/2, MT_PARTICLE);
 	if (!P_MobjWasRemoved(dust))
 	{
-		P_SetScale(dust, 2*FRACUNIT);
+		P_SetScale(dust, 2*FRACUNIT, true);
 		dust->destscale = FRACUNIT/3;
 		dust->scalespeed = FRACUNIT/40;
 		dust->fuse = TICRATE*2;
@@ -2765,15 +2763,9 @@ void A_LobShot(mobj_t *actor)
 		return;
 
 	if (actor->type == MT_BLACKEGGMAN)
-	{
-		shot->destscale = actor->scale/2;
-		P_SetScale(shot, actor->scale/2);
-	}
+		P_SetScale(shot, actor->scale/2, true);
 	else
-	{
-		shot->destscale = actor->scale;
-		P_SetScale(shot, actor->scale);
-	}
+		P_SetScale(shot, actor->scale, true);
 
 	P_SetTarget(&shot->target, actor); // where it came from
 
@@ -3218,8 +3210,7 @@ void A_Boss1Laser(mobj_t *actor)
 		if (!P_MobjWasRemoved(point))
 		{
 			point->angle = actor->angle;
-			point->destscale = actor->scale;
-			P_SetScale(point, point->destscale);
+			P_SetScale(point, actor->scale, true);
 			P_SetTarget(&point->target, actor);
 			P_MobjCheckWater(point);
 			if (point->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))
@@ -3230,7 +3221,8 @@ void A_Boss1Laser(mobj_t *actor)
 					mobj_t *steam = P_SpawnMobj(x, y, point->watertop - size*mobjinfo[MT_DUST].height, MT_DUST);
 					if (P_MobjWasRemoved(steam))
 						continue;
-					P_SetScale(steam, size*actor->scale);
+					P_SetScale(steam, size*actor->scale, false);
+					steam->old_scale = steam->scale;
 					P_SetObjectMomZ(steam, FRACUNIT + 2*P_RandomFixed(), true);
 					P_InstaThrust(steam, FixedAngle(P_RandomKey(360)*FRACUNIT), 2*P_RandomFixed());
 					if (point->info->painsound)
@@ -3603,8 +3595,7 @@ void A_BossScream(mobj_t *actor)
 		return;
 	if (actor->eflags & MFE_VERTICALFLIP)
 		mo->flags2 |= MF2_OBJECTFLIP;
-	mo->destscale = actor->scale;
-	P_SetScale(mo, mo->destscale);
+	P_SetScale(mo, actor->scale, true);
 	if (actor->info->deathsound)
 		S_StartSound(mo, actor->info->deathsound);
 }
@@ -4197,7 +4188,7 @@ static void P_DoBoss5Death(mobj_t *mo)
 				MT_FSGNB);
 			if (!P_MobjWasRemoved(pole))
 			{
-				P_SetScale(pole, (pole->destscale = 2*FRACUNIT));
+				P_SetScale(pole, 2*FRACUNIT, true);
 				pole->momx = P_ReturnThrustX(pole, pole->angle, speed);
 				pole->momy = P_ReturnThrustY(pole, pole->angle, speed);
 				P_SetTarget(&pole->tracer, P_SpawnMobj(
@@ -4207,7 +4198,7 @@ static void P_DoBoss5Death(mobj_t *mo)
 				if (!P_MobjWasRemoved(pole->tracer))
 				{
 					pole->tracer->flags |= MF_NOCLIPTHING;
-					P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT));
+					P_SetScale(pole->tracer, 2*FRACUNIT, true);
 					pole->angle = pole->tracer->angle = mo->tracer->angle;
 					pole->tracer->momx = pole->momx;
 					pole->tracer->momy = pole->momy;
@@ -4746,10 +4737,7 @@ void A_BubbleSpawn(mobj_t *actor)
 		bubble = P_SpawnMobj(actor->x, actor->y, actor->z + (actor->height / 2), MT_MEDIUMBUBBLE);
 
 	if (bubble)
-	{
-		bubble->destscale = actor->scale;
-		P_SetScale(bubble, actor->scale);
-	}
+		P_SetScale(bubble, actor->scale, true);
 }
 
 // Function: A_FanBubbleSpawn
@@ -4792,10 +4780,7 @@ void A_FanBubbleSpawn(mobj_t *actor)
 		bubble = P_SpawnMobj(actor->x, actor->y, hz, MT_MEDIUMBUBBLE);
 
 	if (bubble)
-	{
-		bubble->destscale = actor->scale;
-		P_SetScale(bubble, actor->scale);
-	}
+		P_SetScale(bubble, actor->scale, true);
 }
 
 // Function: A_BubbleRise
@@ -5072,8 +5057,7 @@ void A_ThrownRing(mobj_t *actor)
 			P_SetTarget(&ring->target, actor);
 			ring->color = actor->color; //copy color
 			*/
-			ring->destscale = actor->scale;
-			P_SetScale(ring, actor->scale);
+			P_SetScale(ring, actor->scale, true);
 		}
 	}
 
@@ -5652,8 +5636,7 @@ void A_JetbThink(mobj_t *actor)
 			if (!P_MobjWasRemoved(bomb))
 			{
 				P_SetTarget(&bomb->target, actor);
-				bomb->destscale = actor->scale;
-				P_SetScale(bomb, actor->scale);
+				P_SetScale(bomb, actor->scale, true);
 				actor->reactiontime = TICRATE; // one second
 				S_StartSound(actor, actor->info->attacksound);
 			}
@@ -5833,7 +5816,8 @@ void A_MinusDigging(mobj_t *actor)
 		P_SetMobjState(par, actor->info->raisestate);
 		if (P_MobjWasRemoved(par))
 			return;
-		P_SetScale(par, actor->scale*2);
+		P_SetScale(par, actor->scale*2, false);
+		par->old_scale = par->scale;
 		if (actor->eflags & MFE_VERTICALFLIP)
 			par->eflags |= MFE_VERTICALFLIP;
 		return;
@@ -5905,7 +5889,8 @@ void A_MinusPopup(mobj_t *actor)
 			continue;
 		P_Thrust(rock, ani*i, FRACUNIT);
 		P_SetObjectMomZ(rock, 3*FRACUNIT, false);
-		P_SetScale(rock, rock->scale/3);
+		P_SetScale(rock, rock->scale/3, false);
+		rock->old_scale = rock->scale;
 	}
 	P_RadiusAttack(actor, actor, 2*actor->radius, 0, true);
 	if (actor->tracer)
@@ -5944,7 +5929,8 @@ void A_MinusCheck(mobj_t *actor)
 					continue;
 				P_Thrust(rock, ani*i, FRACUNIT);
 				P_SetObjectMomZ(rock, 3*FRACUNIT, false);
-				P_SetScale(rock, rock->scale/3);
+				P_SetScale(rock, rock->scale/3, false);
+				rock->old_scale = rock->scale;
 			}
 		}
 	}
@@ -8273,8 +8259,9 @@ void A_EggShield(mobj_t *actor)
 	else
 		actor->z = actor->target->z;
 
+	P_SetScale(actor, actor->target->scale, false);
 	actor->destscale = actor->target->destscale;
-	P_SetScale(actor, actor->target->scale);
+	actor->old_scale = actor->target->old_scale;
 
 	actor->floorz = actor->target->floorz;
 	actor->ceilingz = actor->target->ceilingz;
@@ -8555,7 +8542,7 @@ void A_Boss3ShockThink(mobj_t *actor)
 				P_SetTarget(&snew->target, actor->target);
 				snew->fuse = actor->fuse;
 
-				P_SetScale(snew, actor->scale);
+				P_SetScale(snew, actor->scale, true);
 				snew->destscale = actor->destscale;
 				snew->scalespeed = actor->scalespeed;
 
@@ -8757,8 +8744,7 @@ void A_SmokeTrailer(mobj_t *actor)
 	if (P_MobjWasRemoved(th))
 		return;
 	P_SetObjectMomZ(th, FRACUNIT, false);
-	th->destscale = actor->scale;
-	P_SetScale(th, actor->scale);
+	P_SetScale(th, actor->scale, true);
 	th->tics -= P_RandomByte() & 3;
 	if (th->tics < 1)
 		th->tics = 1;
@@ -9522,8 +9508,7 @@ void A_BossJetFume(mobj_t *actor)
 		if (!P_MobjWasRemoved(filler))
 		{
 			P_SetTarget(&filler->target, actor);
-			filler->destscale = actor->scale;
-			P_SetScale(filler, filler->destscale);
+			P_SetScale(filler, actor->scale, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 			filler->fuse = 56;
@@ -9540,8 +9525,7 @@ void A_BossJetFume(mobj_t *actor)
 		if (!P_MobjWasRemoved(filler))
 		{
 			P_SetTarget(&filler->target, actor);
-			filler->destscale = actor->scale;
-			P_SetScale(filler, filler->destscale);
+			P_SetScale(filler, actor->scale, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 			filler->fuse = 57;
@@ -9554,7 +9538,7 @@ void A_BossJetFume(mobj_t *actor)
 		{
 			P_SetTarget(&filler->target, actor);
 			filler->destscale = actor->scale;
-			P_SetScale(filler, filler->destscale);
+			P_SetScale(filler, actor->scale, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 			filler->fuse = 58;
@@ -9575,8 +9559,7 @@ void A_BossJetFume(mobj_t *actor)
 
 		filler = P_SpawnMobj(jetx, jety, jetz, MT_PROPELLER);
 		P_SetTarget(&filler->target, actor);
-		filler->destscale = actor->scale;
-		P_SetScale(filler, filler->destscale);
+		P_SetScale(filler, actor->scale, true);
 		if (actor->eflags & MFE_VERTICALFLIP)
 			filler->flags2 |= MF2_OBJECTFLIP;
 		filler->angle = actor->angle - ANGLE_180;
@@ -9591,7 +9574,7 @@ void A_BossJetFume(mobj_t *actor)
 			P_SetTarget(&filler->target, actor);
 			filler->fuse = 59;
 			P_SetTarget(&actor->tracer, filler);
-			P_SetScale(filler, (filler->destscale = actor->scale/3));
+			P_SetScale(filler, actor->scale/3, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 			filler->color = SKINCOLOR_ICY;
@@ -9610,8 +9593,7 @@ void A_BossJetFume(mobj_t *actor)
 		{
 			P_SetTarget(&filler->target, actor);
 			// Boss 4 already uses its tracer for other things
-			filler->destscale = actor->scale;
-			P_SetScale(filler, filler->destscale);
+			P_SetScale(filler, actor->scale, true);
 			if (actor->eflags & MFE_VERTICALFLIP)
 				filler->flags2 |= MF2_OBJECTFLIP;
 		}
@@ -9633,8 +9615,7 @@ void A_BossJetFume(mobj_t *actor)
 			{
 				filler->movefactor = movefactor;
 				P_SetTarget(&filler->target, actor);
-				filler->destscale = actor->scale;
-				P_SetScale(filler, filler->destscale);
+				P_SetScale(filler, actor->scale, true);
 				if (actor->eflags & MFE_VERTICALFLIP)
 					filler->flags2 |= MF2_OBJECTFLIP;
 			}
@@ -9880,12 +9861,13 @@ void A_ToggleFlameJet(mobj_t* actor)
 // var1 = Angle adjustment (aka orbit speed)
 // var2:
 //        Bits 1-10: height offset, max 1023
-//        Bits 11-16: X radius factor (max 63, default 20)
+//        Bits 11-16: X radius factor (max 63, default 32)
 //        Bit 17: set if object is Nightopian Helper
 //        Bit 18: set to define X/Y/Z rotation factor
-//        Bits 19-20: Unused
+//        Bit 19: set to not sync scale to player
+//        Bit 20: Unused
 //        Bits 21-26: Y radius factor (max 63, default 32)
-//        Bits 27-32: Z radius factor (max 63, default 32)
+//        Bits 27-32: Z radius factor (max 63, default 20)
 //
 // If MF_GRENADEBOUNCE is flagged on mobj, use actor->threshold to define X/Y/Z radius factor, max 1023 each:
 //        Bits 1-10: X factor
@@ -9926,6 +9908,12 @@ void A_OrbitNights(mobj_t* actor)
 	}
 	else
 	{
+		if (!donotrescale)
+		{
+			P_SetScale(actor, actor->target->scale, true);
+			actor->old_scale = actor->target->old_scale;
+		}
+
 		actor->extravalue1 += var1;
 		P_UnsetThingPosition(actor);
 		{
@@ -9953,9 +9941,6 @@ void A_OrbitNights(mobj_t* actor)
 			else
 				actor->flags2 &= ~MF2_DONTDRAW;
 		}
-
-		if (!donotrescale && actor->destscale != actor->target->destscale)
-			actor->destscale = actor->target->destscale;
 	}
 }
 
@@ -11204,9 +11189,10 @@ void A_SetScale(mobj_t *actor)
 		return;
 	}
 
-	target->destscale = locvar1; // destination scale
-	if (!(locvar2 & 65535))
-		P_SetScale(target, locvar1); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 anyway
+	if ((locvar2 & 65535) == 0)
+		P_SetScale(target, locvar1, true); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 over time
+	else
+		target->destscale = locvar1; // destination scale
 }
 
 // Function: A_RemoteDamage
@@ -11350,8 +11336,7 @@ void A_TrapShot(mobj_t *actor)
 	if (actor->eflags & MFE_VERTICALFLIP)
 		missile->flags2 |= MF2_OBJECTFLIP;
 
-	missile->destscale = actor->scale;
-	P_SetScale(missile, actor->scale);
+	P_SetScale(missile, actor->scale, true);
 
 	if (missile->info->seesound)
 		S_StartSound(missile, missile->info->seesound);
@@ -11425,8 +11410,7 @@ void A_VileTarget(mobj_t *actor)
 				fog->eflags |= MFE_VERTICALFLIP;
 				fog->flags2 |= MF2_OBJECTFLIP;
 			}
-			fog->destscale = actor->target->scale;
-			P_SetScale(fog, fog->destscale);
+			P_SetScale(fog, actor->target->scale, true);
 
 			P_SetTarget(&actor->tracer, fog);
 			P_SetTarget(&fog->target, actor);
@@ -11459,8 +11443,7 @@ void A_VileTarget(mobj_t *actor)
 					fog->eflags |= MFE_VERTICALFLIP;
 					fog->flags2 |= MF2_OBJECTFLIP;
 				}
-				fog->destscale = players[i].mo->scale;
-				P_SetScale(fog, fog->destscale);
+				P_SetScale(fog, players[i].mo->scale, true);
 
 				if (players[i].mo == actor->target) // We only care to track the fog targeting who we REALLY hate right now
 					P_SetTarget(&actor->tracer, fog);
@@ -11617,8 +11600,8 @@ void A_VileFire(mobj_t *actor)
 		return;
 
 	// keep to same scale and gravity as tracer ALWAYS
-	actor->destscale = dest->scale;
-	P_SetScale(actor, actor->destscale);
+	P_SetScale(actor, dest->scale, true);
+	actor->old_scale = dest->old_scale;
 	if (dest->eflags & MFE_VERTICALFLIP)
 	{
 		actor->eflags |= MFE_VERTICALFLIP;
@@ -12804,8 +12787,7 @@ void A_LightBeamReset(mobj_t *actor)
 	if (LUA_CallAction(A_LIGHTBEAMRESET, actor))
 		return;
 
-	actor->destscale = FRACUNIT + P_SignedRandom()*FRACUNIT/256;
-	P_SetScale(actor, actor->destscale);
+	P_SetScale(actor, FRACUNIT + P_SignedRandom()*FRACUNIT/256, true);
 
 	if (!actor->spawnpoint)
 		return; // this can't work properly welp
@@ -13392,7 +13374,7 @@ void A_DoNPCSkid(mobj_t *actor)
 		{
 			particle->tics = 10;
 
-			P_SetScale(particle, 2*actor->scale/3);
+			P_SetScale(particle, 2*actor->scale/3, true);
 			particle->destscale = actor->scale;
 			P_SetObjectMomZ(particle, FRACUNIT, false);
 		}
@@ -13815,7 +13797,7 @@ static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fi
 			continue;
 
 		dust->angle = ang*i + ANGLE_90;
-		P_SetScale(dust, FixedMul(initscale, scale));
+		P_SetScale(dust, FixedMul(initscale, scale), true);
 		dust->destscale = FixedMul(4*FRACUNIT + P_RandomFixed(), scale);
 		dust->scalespeed = scale/24;
 		P_Thrust(dust, ang*i, speed + FixedMul(P_RandomFixed(), scale));
@@ -13956,7 +13938,8 @@ void A_DustDevilThink(mobj_t *actor)
 	while (layer && !P_MobjWasRemoved(layer)) {
 		angle_t fa = layer->angle >> ANGLETOFINESHIFT;
 		P_MoveOrigin(layer, layer->x + 5 * FixedMul(scale, FINECOSINE(fa)), layer->y + 5 * FixedMul(scale, FINESINE(fa)), layer->z);
-		layer->scale = scale;
+		P_SetScale(layer, scale, true);
+		layer->old_scale = actor->old_scale;
 		layer->angle += ANG10 / 2;
 		layer->momx = actor->momx;
 		layer->momy = actor->momy;
@@ -13970,8 +13953,7 @@ void A_DustDevilThink(mobj_t *actor)
 		if (!P_MobjWasRemoved(dust))
 		{
 			P_SetMobjState(dust, dust->info->spawnstate + P_RandomRange(0, 2));
-			dust->destscale = scale * 3;
-			P_SetScale(dust, dust->destscale);
+			P_SetScale(dust, 3 * scale, true);
 		}
 	}
 
@@ -13990,6 +13972,7 @@ void A_DustDevilThink(mobj_t *actor)
 			layer = P_SpawnMobj(px, py, pz, MT_DUSTLAYER);
 			if (P_MobjWasRemoved(layer))
 				continue;
+			P_SetScale(layer, scale, true);
 			layer->momz = 5 * scale;
 			layer->angle = ANGLE_90 + ANGLE_90*i;
 			layer->extravalue1 = TICRATE * 3;
@@ -14610,8 +14593,7 @@ void A_MinecartSparkThink(mobj_t *actor)
 			continue;
 		trail->tics = 2;
 		trail->sprite = actor->sprite;
-		P_SetScale(trail, trail->scale/4);
-		trail->destscale = trail->scale;
+		P_SetScale(trail, trail->scale/4, true);
 	}
 }
 
@@ -14734,8 +14716,16 @@ void A_FireShrink(mobj_t *actor)
 	if (LUA_CallAction(A_FIRESHRINK, actor))
 		return;
 
-	actor->destscale = locvar1;
-	actor->scalespeed = FRACUNIT/locvar2;
+	if (locvar2 == 0)
+	{
+		P_SetScale(actor, locvar1, true);
+		actor->scalespeed = FRACUNIT/12; // Reset scalespeed to the default
+	}
+	else
+	{
+		actor->destscale = locvar1;
+		actor->scalespeed = FRACUNIT/locvar2;
+	}
 }
 
 // Function: A_SpawnPterabytes
diff --git a/src/p_inter.c b/src/p_inter.c
index 8584e168a5b2084f3a43443b4fbeca67a594bbab..5534f7865c23afc2d70ceae209e6ea432f6223f8 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -2774,8 +2774,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 				mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE);
 			if (P_MobjWasRemoved(mo))
 				break;
-			mo->destscale = target->scale;
-			P_SetScale(mo, mo->destscale);
+			P_SetScale(mo, target->scale, true);
 			P_SetMobjState(mo, mo->info->raisestate);
 			break;
 
@@ -3966,8 +3965,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
 		mo->fuse = 8*TICRATE;
 		P_SetTarget(&mo->target, player->mo);
 
-		mo->destscale = player->mo->scale;
-		P_SetScale(mo, player->mo->scale);
+		P_SetScale(mo, player->mo->scale, true);
 
 		// Angle offset by player angle, then slightly offset by amount of rings
 		fa = ((i*FINEANGLES/16) + va - ((num_rings-1)*FINEANGLES/32)) & FINEMASK;
@@ -4103,8 +4101,7 @@ void P_PlayerWeaponPanelBurst(player_t *player)
 		mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT);
 		P_SetTarget(&mo->target, player->mo);
 		mo->fuse = 12*TICRATE;
-		mo->destscale = player->mo->scale;
-		P_SetScale(mo, player->mo->scale);
+		P_SetScale(mo, player->mo->scale, true);
 
 		// Angle offset by player angle
 		fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK;
@@ -4192,8 +4189,7 @@ void P_PlayerWeaponAmmoBurst(player_t *player)
 		player->powers[power] = 0;
 		mo->fuse = 12*TICRATE;
 
-		mo->destscale = player->mo->scale;
-		P_SetScale(mo, player->mo->scale);
+		P_SetScale(mo, player->mo->scale, true);
 
 		// Angle offset by player angle
 		fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK;
@@ -4240,8 +4236,7 @@ void P_PlayerWeaponPanelOrAmmoBurst(player_t *player)
 			mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \
 			P_SetTarget(&mo->target, player->mo); \
 			mo->fuse = 12*TICRATE; \
-			mo->destscale = player->mo->scale; \
-			P_SetScale(mo, player->mo->scale); \
+			P_SetScale(mo, player->mo->scale, true); \
 			mo->momx = FixedMul(FINECOSINE(fa),ns); \
 			if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \
 				mo->momy = FixedMul(FINESINE(fa),ns); \
@@ -4263,8 +4258,7 @@ void P_PlayerWeaponPanelOrAmmoBurst(player_t *player)
 			mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); \
 			P_SetTarget(&mo->target, player->mo); \
 			mo->fuse = 12*TICRATE; \
-			mo->destscale = player->mo->scale; \
-			P_SetScale(mo, player->mo->scale); \
+			P_SetScale(mo, player->mo->scale, true); \
 			mo->momx = FixedMul(FINECOSINE(fa),ns); \
 			if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) \
 				mo->momy = FixedMul(FINESINE(fa),ns); \
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 715e8797427a3fe155fe6a107dda0735f923b3f0..55be8e54fc4e36684e20279ac134d7de4772780f 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -917,7 +917,7 @@ void P_ExplodeMissile(mobj_t *mo)
 		explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
 		if (!P_MobjWasRemoved(explodemo))
 		{
-			P_SetScale(explodemo, mo->scale);
+			P_SetScale(explodemo, mo->scale, true);
 			explodemo->destscale = mo->destscale;
 			explodemo->momx += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale);
 			explodemo->momy += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale);
@@ -926,7 +926,7 @@ void P_ExplodeMissile(mobj_t *mo)
 		explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
 		if (!P_MobjWasRemoved(explodemo))
 		{
-			P_SetScale(explodemo, mo->scale);
+			P_SetScale(explodemo, mo->scale, true);
 			explodemo->destscale = mo->destscale;
 			explodemo->momx += (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale);
 			explodemo->momy -= (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale);
@@ -935,7 +935,7 @@ void P_ExplodeMissile(mobj_t *mo)
 		explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
 		if (!P_MobjWasRemoved(explodemo))
 		{
-			P_SetScale(explodemo, mo->scale);
+			P_SetScale(explodemo, mo->scale, true);
 			explodemo->destscale = mo->destscale;
 			explodemo->momx -= (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale);
 			explodemo->momy += (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale);
@@ -944,7 +944,7 @@ void P_ExplodeMissile(mobj_t *mo)
 		explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
 		if (!P_MobjWasRemoved(explodemo))
 		{
-			P_SetScale(explodemo, mo->scale);
+			P_SetScale(explodemo, mo->scale, true);
 			explodemo->destscale = mo->destscale;
 			explodemo->momx -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale);
 			explodemo->momy -= (P_RandomByte() % 96) * FixedMul(FRACUNIT/8, explodemo->scale);
@@ -3113,8 +3113,7 @@ boolean P_SceneryZMovement(mobj_t *mo)
 						continue;
 					explodemo->momx += ((prandom & 0x0F) << (FRACBITS-2)) * (i & 2 ? -1 : 1);
 					explodemo->momy += ((prandom & 0xF0) << (FRACBITS-6)) * (i & 1 ? -1 : 1);
-					explodemo->destscale = mo->scale;
-					P_SetScale(explodemo, mo->scale);
+					P_SetScale(explodemo, mo->scale, true);
 				}
 
 				if (mo->threshold != 42) // Don't make pop sound if threshold is 42.
@@ -3140,7 +3139,7 @@ boolean P_SceneryZMovement(mobj_t *mo)
 				mobj_t *flower = P_SpawnMobjFromMobj(mo, 0, 0, 0, flowertype);
 				if (flower)
 				{
-					P_SetScale(flower, mo->scale/16);
+					P_SetScale(flower, mo->scale/16, true);
 					flower->destscale = mo->scale;
 					flower->scalespeed = mo->scale/8;
 				}
@@ -3380,10 +3379,7 @@ void P_MobjCheckWater(mobj_t *mobj)
 				else
 					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype);
 				if (!P_MobjWasRemoved(splish))
-				{
-					splish->destscale = mobj->scale;
-					P_SetScale(splish, mobj->scale);
-				}
+					P_SetScale(splish, mobj->scale, true);
 			}
 
 			// skipping stone!
@@ -3422,10 +3418,7 @@ void P_MobjCheckWater(mobj_t *mobj)
 				else
 					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype);
 				if (!P_MobjWasRemoved(splish))
-				{
-					splish->destscale = mobj->scale;
-					P_SetScale(splish, mobj->scale);
-				}
+					P_SetScale(splish, mobj->scale, true);
 			}
 		}
 
@@ -3476,8 +3469,7 @@ void P_MobjCheckWater(mobj_t *mobj)
 					else
 						bubble->momz = 0;
 
-					bubble->destscale = mobj->scale;
-					P_SetScale(bubble, mobj->scale);
+					P_SetScale(bubble, mobj->scale, true);
 				}
 			}
 		}
@@ -5147,8 +5139,7 @@ static void P_Boss7Thinker(mobj_t *mobj)
 		mobj_t *smoke = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height, MT_SMOKE);
 		if (!P_MobjWasRemoved(smoke))
 		{
-			smoke->destscale = mobj->destscale;
-			P_SetScale(smoke, smoke->destscale);
+			P_SetScale(smoke, mobj->destscale, true);
 			smoke->momz = FixedMul(FRACUNIT, smoke->scale);
 		}
 	}
@@ -5599,7 +5590,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 				if (mobj->hprev)
 				{
 					mobj->hprev->destscale = FRACUNIT + (2*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2);
-					P_SetScale(mobj->hprev, mobj->hprev->destscale);
+					P_SetScale(mobj->hprev, mobj->hprev->destscale, false);
 
 					P_MoveOrigin(mobj->hprev, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->hprev->height/2);
 					mobj->hprev->momx = mobj->momx;
@@ -5625,8 +5616,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
 						{
 							S_StopSound(missile);
 							if (mobj->extravalue1 >= 2)
-								P_SetScale(missile, FRACUNIT>>1);
-							missile->destscale = missile->scale>>1;
+								P_SetScale(missile, FRACUNIT/2, true);
+							missile->destscale = missile->scale/2;
 							missile->fuse = TICRATE/2;
 							missile->scalespeed = abs(missile->destscale - missile->scale)/missile->fuse;
 							missile->z -= missile->height/2;
@@ -5649,7 +5640,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 									spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2);
 									P_InstaThrust(spread,spread->angle,-spread->info->speed);
 									spread->momz = missile->momz;
-									P_SetScale(spread, missile->scale);
+									P_SetScale(spread, missile->scale, true);
 									spread->destscale = missile->destscale;
 									spread->scalespeed = missile->scalespeed;
 									spread->fuse = missile->fuse;
@@ -5673,7 +5664,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 										spread = P_SpawnMissile(mobj, mobj->target, missile->type);
 										if (P_MobjWasRemoved(spread))
 											continue;
-										P_SetScale(spread, missile->scale);
+										P_SetScale(spread, missile->scale, true);
 										spread->destscale = missile->destscale;
 										spread->fuse = missile->fuse;
 										spread->z -= spread->height/2;
@@ -5730,12 +5721,12 @@ static void P_Boss9Thinker(mobj_t *mobj)
 					{
 						if (mobj->health > mobj->info->damage)
 						{
-							P_SetScale(missile, FRACUNIT/3);
+							P_SetScale(missile, FRACUNIT/3, true);
 							missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power
 						}
 						else
 						{
-							P_SetScale(missile, FRACUNIT/5);
+							P_SetScale(missile, FRACUNIT/5, true);
 							missile->color = SKINCOLOR_SUNSET; // sonic cd electric power
 						}
 						missile->destscale = missile->scale*2;
@@ -5798,10 +5789,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 					if (!P_MobjWasRemoved(missile))
 					{
 						if (mobj->extravalue1 >= 2)
-						{
-							missile->destscale = FRACUNIT>>1;
-							P_SetScale(missile, missile->destscale);
-						}
+							P_SetScale(missile, FRACUNIT/2, true);
 						missile->fuse = 3*TICRATE;
 						missile->z -= missile->height/2;
 
@@ -5820,8 +5808,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 								spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2);
 								P_InstaThrust(spread,spread->angle,spread->info->speed);
 								spread->momz = missile->momz;
-								spread->destscale = FRACUNIT>>1;
-								P_SetScale(spread, spread->destscale);
+								P_SetScale(spread, FRACUNIT/2, true);
 								spread->fuse = missile->fuse;
 							}
 							P_InstaThrust(missile,missile->angle,missile->info->speed);
@@ -5838,8 +5825,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
 									spread = P_SpawnMissile(mobj, mobj->target, missile->type);
 									if (!P_MobjWasRemoved(spread))
 									{
-										spread->destscale = FRACUNIT>>1;
-										P_SetScale(spread, spread->destscale);
+										P_SetScale(spread, FRACUNIT/2, true);
 										spread->fuse = missile->fuse;
 										spread->z -= spread->height/2;
 									}
@@ -6103,8 +6089,12 @@ static void P_Boss9Thinker(mobj_t *mobj)
 					whoosh->flags |= MF_NOCLIPHEIGHT;
 #endif
 
-					P_SetMobjState(mobj->tracer, S_JETFUMEFLASH);
-					P_SetScale(mobj->tracer, mobj->scale << 1);
+					if (!P_MobjWasRemoved(mobj->tracer))
+					{
+						P_SetMobjState(mobj->tracer, S_JETFUMEFLASH);
+						P_SetScale(mobj->tracer, 2*mobj->scale, false);
+						mobj->tracer->old_scale = mobj->tracer->scale;
+					}
 				}
 				else
 				{
@@ -6439,28 +6429,24 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb
 //
 // Sets the sprite scaling
 //
-void P_SetScale(mobj_t *mobj, fixed_t newscale)
+void P_SetScale(mobj_t *mobj, fixed_t newscale, boolean instant)
 {
-	player_t *player;
-	fixed_t oldscale;
-
 	if (!mobj)
 		return;
 
-	oldscale = mobj->scale; //keep for adjusting stuff below
-
-	mobj->scale = newscale;
-
-	mobj->radius = FixedMul(FixedDiv(mobj->radius, oldscale), newscale);
-	mobj->height = FixedMul(FixedDiv(mobj->height, oldscale), newscale);
-
-	player = mobj->player;
-
-	if (player)
+	if (mobj->player)
 	{
 		G_GhostAddScale(newscale);
-		player->viewheight = FixedMul(FixedDiv(player->viewheight, oldscale), newscale); // Nonono don't calculate viewheight elsewhere, this is the best place for it!
+		// Nonono don't calculate viewheight elsewhere, this is the best place for it!
+		mobj->player->viewheight = FixedMul(FixedDiv(mobj->player->viewheight, mobj->scale), newscale);
 	}
+
+	mobj->radius = FixedMul(FixedDiv(mobj->radius, mobj->scale), newscale);
+	mobj->height = FixedMul(FixedDiv(mobj->height, mobj->scale), newscale);
+
+	mobj->scale = newscale;
+	if (instant)
+		mobj->destscale = mobj->old_scale = newscale;
 }
 
 void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on your target
@@ -6815,8 +6801,7 @@ static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
 	thing->flags |= MF_NOCLIPHEIGHT;
 	thing->eflags = (thing->eflags & ~MFE_VERTICALFLIP)|(thing->target->eflags & MFE_VERTICALFLIP);
 
-	P_SetScale(thing, FixedMul(thing->target->scale, thing->target->player->shieldscale));
-	thing->destscale = thing->scale;
+	P_SetScale(thing, FixedMul(thing->target->scale, thing->target->player->shieldscale), true);
 	thing->old_scale = FixedMul(thing->target->old_scale, thing->target->player->shieldscale);
 
 #define NewMH(mobj)   mobj->height // Ugly mobj-height and player-height defines, for the sake of prettier code
@@ -7164,11 +7149,11 @@ static void P_MobjScaleThink(mobj_t *mobj)
 		correctionType = 2; // Correct Z position by moving down
 
 	if (abs(mobj->scale - mobj->destscale) < mobj->scalespeed)
-		P_SetScale(mobj, mobj->destscale);
+		P_SetScale(mobj, mobj->destscale, false);
 	else if (mobj->scale < mobj->destscale)
-		P_SetScale(mobj, mobj->scale + mobj->scalespeed);
+		P_SetScale(mobj, mobj->scale + mobj->scalespeed, false);
 	else if (mobj->scale > mobj->destscale)
-		P_SetScale(mobj, mobj->scale - mobj->scalespeed);
+		P_SetScale(mobj, mobj->scale - mobj->scalespeed, false);
 
 	if (correctionType == 1)
 		mobj->z -= (mobj->height - oldheight)/2;
@@ -7261,8 +7246,9 @@ static boolean P_DrownNumbersSceneryThink(mobj_t *mobj)
 	mobj->x = mobj->target->x;
 	mobj->y = mobj->target->y;
 
+	P_SetScale(mobj, mobj->target->scale, false);
 	mobj->destscale = mobj->target->destscale;
-	P_SetScale(mobj, mobj->target->scale);
+	mobj->old_scale = mobj->target->old_scale;
 
 	if (mobj->target->eflags & MFE_VERTICALFLIP)
 	{
@@ -7423,10 +7409,10 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj)
 				(mobjtype_t)mobj->threshold);
 			if (!P_MobjWasRemoved(spawn))
 			{
-				P_SetScale(spawn, mobj->scale);
-				spawn->momz = FixedMul(mobj->movefactor, spawn->scale);
+				P_SetScale(spawn, mobj->scale, true);
 				spawn->destscale = spawn->scale/100;
 				spawn->scalespeed = spawn->scale/mobj->health;
+				spawn->momz = FixedMul(mobj->movefactor, spawn->scale);
 				spawn->tics = (tic_t)mobj->health;
 				spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP);
 				spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones
@@ -7646,8 +7632,7 @@ static void P_RosySceneryThink(mobj_t *mobj)
 			mobj_t *cdlhrt = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_CDLHRT);
 			if (!P_MobjWasRemoved(cdlhrt))
 			{
-				cdlhrt->destscale = (5*mobj->scale) >> 4;
-				P_SetScale(cdlhrt, cdlhrt->destscale);
+				P_SetScale(cdlhrt, (5*mobj->scale) >> 4, true);
 				cdlhrt->fuse = (5*TICRATE) >> 1;
 				cdlhrt->momz = mobj->scale;
 				P_SetTarget(&cdlhrt->target, mobj);
@@ -7901,8 +7886,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
 
 		mobj->eflags |= (mobj->target->eflags & MFE_VERTICALFLIP);
 
+		P_SetScale(mobj, mobj->target->scale, false);
 		mobj->destscale = mobj->target->destscale;
-		P_SetScale(mobj, mobj->target->scale);
+		mobj->old_scale = mobj->target->old_scale;
 
 		if (!(mobj->eflags & MFE_VERTICALFLIP))
 			mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale);
@@ -8052,7 +8038,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
 		}
 		P_SetThingPosition(mobj);
 
-		P_SetScale(mobj, mobj->target->scale);
+		P_SetScale(mobj, mobj->target->scale, false);
+		mobj->destscale = mobj->target->destscale;
+		mobj->old_scale = mobj->target->old_scale;
 	}
 	break;
 	case MT_TUTORIALFLOWER:
@@ -8494,8 +8482,8 @@ static void P_ArrowThink(mobj_t *mobj)
 			if (!P_MobjWasRemoved(dust))
 			{
 				dust->tics = 18;
-				dust->scalespeed = 4096;
 				dust->destscale = FRACUNIT/32;
+				dust->scalespeed = FRACUNIT/16;
 			}
 		}
 	}
@@ -9906,9 +9894,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
 			traindust->frame = P_RandomRange(0, 8)|FF_TRANS90;
 			traindust->angle = mobj->angle;
 			traindust->tics = TICRATE*4;
+			P_SetScale(traindust, FRACUNIT*6, true);
 			traindust->destscale = FRACUNIT*64;
 			traindust->scalespeed = FRACUNIT/24;
-			P_SetScale(traindust, FRACUNIT*6);
 		}
 		break;
 	case MT_TRAINSTEAMSPAWNER:
@@ -9919,9 +9907,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
 			P_SetMobjState(steam, S_TRAINSTEAM);
 			steam->frame = P_RandomRange(0, 1)|FF_TRANS90;
 			steam->tics = TICRATE*8;
+			P_SetScale(steam, FRACUNIT*16, true);
 			steam->destscale = FRACUNIT*64;
 			steam->scalespeed = FRACUNIT/8;
-			P_SetScale(steam, FRACUNIT*16);
 			steam->momx = P_SignedRandom()*32;
 			steam->momy = -64*FRACUNIT;
 			steam->momz = 2*FRACUNIT;
@@ -10927,7 +10915,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 			if (titlemapinaction) mobj->flags &= ~MF_NOTHINK;
 			break;
 		case MT_LOCKONINF:
-			P_SetScale(mobj, (mobj->destscale = 3*mobj->scale));
+			P_SetScale(mobj, 3*mobj->scale, true);
 			break;
 		case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE:
 			mobj->fuse = mobj->info->painchance;
@@ -10938,8 +10926,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 				if (P_MobjWasRemoved(spawn))
 					break;
 
-				spawn->destscale = mobj->scale;
-				P_SetScale(spawn, mobj->scale);
+				P_SetScale(spawn, mobj->scale, true);
 				P_SetTarget(&spawn->target, mobj);
 			}
 			break;
@@ -10956,8 +10943,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 				if (P_MobjWasRemoved(spawn))
 					break;
 
-				spawn->destscale = mobj->scale;
-				P_SetScale(spawn, mobj->scale);
+				P_SetScale(spawn, mobj->scale, true);
 				P_SetTarget(&mobj->tracer, spawn);
 				P_SetTarget(&spawn->target, mobj);
 			}
@@ -10974,8 +10960,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 					if (P_MobjWasRemoved(ball))
 						continue;
 
-					ball->destscale = mobj->scale;
-					P_SetScale(ball, mobj->scale);
+					P_SetScale(ball, mobj->scale, true);
 					P_SetTarget(&ball->target, mobj);
 					ball->movedir = FixedAngle(FixedMul(FixedDiv(i<<FRACBITS, mobj->info->damage<<FRACBITS), 360<<FRACBITS));
 					ball->threshold = ball->radius + mobj->radius + FixedMul(ball->info->painchance, ball->scale);
@@ -10996,8 +10981,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type, ...)
 					if (P_MobjWasRemoved(ball))
 						continue;
 
-					ball->destscale = mobj->scale;
-					P_SetScale(ball, mobj->scale);
+					P_SetScale(ball, mobj->scale, true);
 					P_SetTarget(&lastball->tracer, ball);
 					P_SetTarget(&ball->target, mobj);
 					lastball = ball;
@@ -11856,7 +11840,7 @@ void P_SpawnPlayer(INT32 playernum)
 	p->awayviewtics = 0;
 
 	// set the scale to the mobj's destscale so settings get correctly set.  if we don't, they sometimes don't.
-	P_SetScale(mobj, mobj->destscale);
+	P_SetScale(mobj, mobj->destscale, true);
 	P_FlashPal(p, 0, 0); // Resets
 
 	// Set bounds accurately.
@@ -12030,7 +12014,7 @@ void P_MovePlayerToStarpost(INT32 playernum)
 
 	z = p->starpostz << FRACBITS;
 
-	P_SetScale(mobj, (mobj->destscale = abs(p->starpostscale)));
+	P_SetScale(mobj, abs(p->starpostscale), true);
 
 	if (p->starpostscale < 0)
 	{
@@ -13138,8 +13122,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 			if (P_MobjWasRemoved(corona))
 				break;
 
-			P_SetScale(corona, (corona->destscale = mobj->scale*3));
 			P_SetTarget(&mobj->tracer, corona);
+			P_SetScale(corona, 3*mobj->scale, true);
 		}
 		break;
 	case MT_FLAMEHOLDER:
@@ -13157,8 +13141,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 				if (P_MobjWasRemoved(corona))
 					break;
 
-				P_SetScale(corona, (corona->destscale = flame->scale*3));
 				P_SetTarget(&flame->tracer, corona);
+				P_SetScale(corona, 3*flame->scale, true);
 			}
 		}
 		break;
@@ -13246,10 +13230,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 	case MT_DSZSTALAGMITE:
 	case MT_DSZ2STALAGMITE:
 	case MT_KELP:
-		if (mthing->args[0]) { // make mobj twice as big as normal
-			P_SetScale(mobj, 2*mobj->scale); // not 2*FRACUNIT in case of something like the old ERZ3 mode
-			mobj->destscale = mobj->scale;
-		}
+		if (mthing->args[0]) // make mobj twice as big as normal
+			P_SetScale(mobj, 2*mobj->scale, true); // not 2*FRACUNIT in case of something like the old ERZ3 mode
 		break;
 	case MT_THZTREE:
 	{ // Spawn the branches
@@ -13328,10 +13310,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 	case MT_LAVAFALL:
 		mobj->fuse = 30 + mthing->args[0];
 		if (mthing->args[1])
-		{
-			P_SetScale(mobj, 2*mobj->scale);
-			mobj->destscale = mobj->scale;
-		}
+			P_SetScale(mobj, 2*mobj->scale, true);
 		break;
 	case MT_PYREFLY:
 		//start on fire if args[0], otherwise behave normally
@@ -13394,8 +13373,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 				break;
 			P_SetTarget(&elecmobj->target, mobj);
 			elecmobj->angle = FixedAngle(mthing->angle << FRACBITS);
-			elecmobj->destscale = mobj->scale*2;
-			P_SetScale(elecmobj, elecmobj->destscale);
+			P_SetScale(elecmobj, 2*mobj->scale, true);
 		}
 		break;
 	case MT_STARPOST:
@@ -13453,8 +13431,8 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 				return false;
 			}
 			base->angle = mobjangle + ANGLE_90;
+			P_SetScale(base, mobj->scale, true);
 			base->destscale = mobj->destscale;
-			P_SetScale(base, mobj->scale);
 			P_SetTarget(&base->target, mobj);
 			P_SetTarget(&mobj->tracer, base);
 		}
@@ -13631,8 +13609,9 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y,
 		return NULL;
 	mobj->spawnpoint = mthing;
 
-	P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale));
+	P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale), false);
 	mobj->destscale = FixedMul(mobj->destscale, mthing->scale);
+	mobj->old_scale = FixedMul(mobj->old_scale, mthing->scale);
 
 	mobj->spritexscale = mthing->spritexscale;
 	mobj->spriteyscale = mthing->spriteyscale;
@@ -14086,8 +14065,7 @@ mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type,
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	speed = FixedMul(th->info->speed, th->scale);
 
@@ -14150,8 +14128,7 @@ mobj_t *P_SpawnAlteredDirectionMissile(mobj_t *source, mobjtype_t type, fixed_t
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	speed = FixedMul(th->info->speed, th->scale);
 
@@ -14217,8 +14194,7 @@ mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za,
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	speed = FixedMul(th->info->speed, th->scale);
 
@@ -14289,8 +14265,7 @@ mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	if (source->type == MT_METALSONIC_BATTLE && source->health < 4)
 		speed = FixedMul(FixedMul(th->info->speed, 3*FRACUNIT/2), th->scale);
@@ -14392,8 +14367,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai
 	if (source->eflags & MFE_VERTICALFLIP)
 		th->flags2 |= MF2_OBJECTFLIP;
 
-	th->destscale = source->scale;
-	P_SetScale(th, source->scale);
+	P_SetScale(th, source->scale, true);
 
 	th->flags2 |= flags2;
 
@@ -14475,8 +14449,8 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo
 		newmobj->old_z2 = mobj->old_z2 + zofs;
 	}
 
+	P_SetScale(newmobj, mobj->scale, false);
 	newmobj->destscale = mobj->destscale;
-	P_SetScale(newmobj, mobj->scale);
 
 	newmobj->old_x2 = mobj->old_x2 + xofs;
 	newmobj->old_y2 = mobj->old_y2 + yofs;
@@ -14505,9 +14479,13 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo
 
 	newmobj->old_scale2 = mobj->old_scale2;
 	newmobj->old_scale = mobj->old_scale;
+	newmobj->old_spritexscale2 = mobj->old_spritexscale2;
 	newmobj->old_spritexscale = mobj->old_spritexscale;
+	newmobj->old_spriteyscale2 = mobj->old_spriteyscale2;
 	newmobj->old_spriteyscale = mobj->old_spriteyscale;
+	newmobj->old_spritexoffset2 = mobj->old_spritexoffset2;
 	newmobj->old_spritexoffset = mobj->old_spritexoffset;
+	newmobj->old_spriteyoffset2 = mobj->old_spriteyoffset2;
 	newmobj->old_spriteyoffset = mobj->old_spriteyoffset;
 
 	return newmobj;
diff --git a/src/p_mobj.h b/src/p_mobj.h
index f833415ed1d0af3ee377ed6d4ced943d2782f499..fd75f75c6ef5e6022e55cfbe69a25043e1f0d6a5 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -315,8 +315,8 @@ typedef struct mobj_s
 	INT32 blendmode; // blend mode
 	fixed_t spritexscale, spriteyscale;
 	fixed_t spritexoffset, spriteyoffset;
-	fixed_t old_spritexscale, old_spriteyscale;
-	fixed_t old_spritexoffset, old_spriteyoffset;
+	fixed_t old_spritexscale, old_spriteyscale, old_spritexscale2, old_spriteyscale2;
+	fixed_t old_spritexoffset, old_spriteyoffset, old_spritexoffset2, old_spriteyoffset2;
 	struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by
 
 	struct msecnode_s *touching_sectorlist; // a linked list of sectors where this object appears
@@ -458,8 +458,8 @@ typedef struct precipmobj_s
 	INT32 blendmode; // blend mode
 	fixed_t spritexscale, spriteyscale;
 	fixed_t spritexoffset, spriteyoffset;
-	fixed_t old_spritexscale, old_spriteyscale;
-	fixed_t old_spritexoffset, old_spriteyoffset;
+	fixed_t old_spritexscale, old_spriteyscale, old_spritexscale2, old_spriteyscale2;
+	fixed_t old_spritexoffset, old_spriteyoffset, old_spritexoffset2, old_spriteyoffset2;
 	struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by
 
 	struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears
@@ -527,7 +527,7 @@ void P_SnowThinker(precipmobj_t *mobj);
 void P_RainThinker(precipmobj_t *mobj);
 void P_NullPrecipThinker(precipmobj_t *mobj);
 void P_RemovePrecipMobj(precipmobj_t *mobj);
-void P_SetScale(mobj_t *mobj, fixed_t newscale);
+void P_SetScale(mobj_t *mobj, fixed_t newscale, boolean instant);
 void P_XYMovement(mobj_t *mo);
 void P_RingXYMovement(mobj_t *mo);
 void P_SceneryXYMovement(mobj_t *mo);
diff --git a/src/p_user.c b/src/p_user.c
index 9fc1f8c9b4dcbf9dcb7f589b5283f474ff5ac843..b55a9376412b836ce933593108647ee707a17ff2 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -2038,8 +2038,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
 	P_SetTarget(&ghost->target, mobj);
 	P_SetTarget(&ghost->dontdrawforviewmobj, mobj); // Hide the ghost in first-person
 
-	P_SetScale(ghost, mobj->scale);
-	ghost->destscale = mobj->scale;
+	P_SetScale(ghost, mobj->scale, true);
 
 	if (mobj->eflags & MFE_VERTICALFLIP)
 	{
@@ -2098,6 +2097,11 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
 	ghost->old_pitch = mobj->old_pitch2;
 	ghost->old_roll = mobj->old_roll2;
 	ghost->old_spriteroll = mobj->old_spriteroll2;
+	ghost->old_spritexscale = mobj->old_spritexscale2;
+	ghost->old_spriteyscale = mobj->old_spriteyscale2;
+	ghost->old_spritexoffset = mobj->old_spritexoffset2;
+	ghost->old_spriteyoffset = mobj->old_spriteyoffset2;
+	ghost->old_scale = mobj->old_scale2;
 
 	return ghost;
 }
@@ -2153,7 +2157,7 @@ void P_SpawnThokMobj(player_t *player)
 		mobj->eflags |= (player->mo->eflags & MFE_VERTICALFLIP);
 
 		// scale
-		P_SetScale(mobj, (mobj->destscale = player->mo->scale));
+		P_SetScale(mobj, player->mo->scale, true);
 
 		if (type == MT_THOK) // spintrail-specific modification for MT_THOK
 		{
@@ -2217,8 +2221,7 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
 		mobj->eflags |= (player->mo->eflags & MFE_VERTICALFLIP);
 
 		// scale
-		P_SetScale(mobj, player->mo->scale);
-		mobj->destscale = player->mo->scale;
+		P_SetScale(mobj, player->mo->scale, true);
 
 		if (type == MT_THOK) // spintrail-specific modification for MT_THOK
 		{
@@ -3041,9 +3044,8 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
 					P_SetMobjState(numbermobj, numbermobj->info->spawnstate+timeleft);
 
 				P_SetTarget(&numbermobj->target, player->mo);
+				P_SetScale(numbermobj, player->mo->scale, true);
 				numbermobj->threshold = 40;
-				numbermobj->destscale = player->mo->scale;
-				P_SetScale(numbermobj, player->mo->scale);
 			}
 		}
 	}
@@ -3105,10 +3107,7 @@ static void P_CheckInvincibilityTimer(player_t *player)
 	{
 		mobj_t *sparkle = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_IVSP);
 		if (!P_MobjWasRemoved(sparkle))
-		{
-			sparkle->destscale = player->mo->scale;
-			P_SetScale(sparkle, player->mo->scale);
-		}
+			P_SetScale(sparkle, player->mo->scale, true);
 	}
 
 	// Resume normal music stuff.
@@ -3183,8 +3182,7 @@ static void P_DoBubbleBreath(player_t *player)
 	if (bubble)
 	{
 		bubble->threshold = 42;
-		bubble->destscale = player->mo->scale;
-		P_SetScale(bubble, bubble->destscale);
+		P_SetScale(bubble, player->mo->scale, true);
 	}
 
 	// Tails stirs up the water while flying in it
@@ -3206,20 +3204,14 @@ static void P_DoBubbleBreath(player_t *player)
 			player->mo->y + stirwatery,
 			stirwaterz, MT_SMALLBUBBLE);
 		if (!P_MobjWasRemoved(bubble))
-		{
-			bubble->destscale = player->mo->scale;
-			P_SetScale(bubble,bubble->destscale);
-		}
+			P_SetScale(bubble, player->mo->scale, true);
 
 		bubble = P_SpawnMobj(
 			player->mo->x - stirwaterx,
 			player->mo->y - stirwatery,
 			stirwaterz, MT_SMALLBUBBLE);
 		if (!P_MobjWasRemoved(bubble))
-		{
-			bubble->destscale = player->mo->scale;
-			P_SetScale(bubble,bubble->destscale);
-		}
+			P_SetScale(bubble, player->mo->scale, true);
 	}
 }
 
@@ -4424,10 +4416,7 @@ static void P_DoSuperStuff(player_t *player)
 		{
 			spark = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK);
 			if (!P_MobjWasRemoved(spark))
-			{
-				spark->destscale = player->mo->scale;
-				P_SetScale(spark, player->mo->scale);
-			}
+				P_SetScale(spark, player->mo->scale, true);
 		}
 
 		// Ran out of rings while super!
@@ -4677,8 +4666,7 @@ void P_DoSpinDashDust(player_t *player)
 			P_SetMobjState(particle, S_SPINDUST_FIRE1);
 
 		P_SetTarget(&particle->target, player->mo);
-		particle->destscale = (2*player->mo->scale)/3;
-		P_SetScale(particle, particle->destscale);
+		P_SetScale(particle, (2*player->mo->scale)/3, true);
 		if (player->mo->eflags & MFE_VERTICALFLIP) // readjust z position if needed
 			particle->z = player->mo->z + player->mo->height - particle->height;
 		prandom[0] = P_RandomFixed()<<2; // P_RandomByte()<<10
@@ -5077,7 +5065,7 @@ void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type)
 		if (!P_MobjWasRemoved(missile))
 		{
 			P_SetTarget(&missile->target, player->mo);
-			P_SetScale(missile, (missile->destscale >>= 1));
+			P_SetScale(missile, missile->destscale/2, true);
 			missile->angle = ang + movang;
 			missile->fuse = TICRATE/2;
 			missile->extravalue2 = (99*FRACUNIT)/100;
@@ -7417,9 +7405,8 @@ static void P_NiGHTSMovement(player_t *player)
 		firstmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle+ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle+ANGLE_90, spawndist), z, MT_NIGHTSPARKLE);
 		if (!P_MobjWasRemoved(firstmobj))
 		{
-			firstmobj->destscale = player->mo->scale;
 			P_SetTarget(&firstmobj->target, player->mo);
-			P_SetScale(firstmobj, player->mo->scale);
+			P_SetScale(firstmobj, player->mo->scale, true);
 			// Superloop turns sparkles red
 			if (player->powers[pw_nights_superloop])
 				P_SetMobjState(firstmobj, mobjinfo[MT_NIGHTSPARKLE].seestate);
@@ -7427,10 +7414,8 @@ static void P_NiGHTSMovement(player_t *player)
 		secondmobj = P_SpawnMobj(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle-ANGLE_90, spawndist), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle-ANGLE_90, spawndist), z, MT_NIGHTSPARKLE);
 		if (!P_MobjWasRemoved(secondmobj))
 		{
-			secondmobj->destscale = player->mo->scale;
 			P_SetTarget(&secondmobj->target, player->mo);
-			P_SetScale(secondmobj, player->mo->scale);
-
+			P_SetScale(secondmobj, player->mo->scale, true);
 			// Superloop turns sparkles red
 			if (player->powers[pw_nights_superloop])
 				P_SetMobjState(secondmobj, mobjinfo[MT_NIGHTSPARKLE].seestate);
@@ -7445,7 +7430,7 @@ static void P_NiGHTSMovement(player_t *player)
 		{
 			helpermobj->fuse = player->mo->fuse = leveltime;
 			P_SetTarget(&helpermobj->target, player->mo);
-			P_SetScale(helpermobj, player->mo->scale);
+			P_SetScale(helpermobj, player->mo->scale, false);
 		}
 	}
 
@@ -7645,8 +7630,7 @@ static void P_NiGHTSMovement(player_t *player)
 				water->flags2 |= MF2_OBJECTFLIP;
 				water->eflags |= MFE_VERTICALFLIP;
 			}
-			water->destscale = player->mo->scale;
-			P_SetScale(water, player->mo->scale);
+			P_SetScale(water, player->mo->scale, true);
 		}
 	}
 
@@ -7889,8 +7873,7 @@ void P_ElementalFire(player_t *player, boolean cropcircle)
 			P_SetTarget(&flame->target, player->mo);
 			flame->angle = travelangle + i*(ANGLE_MAX/numangles);
 			flame->fuse = TICRATE*7; // takes about an extra second to hit the ground
-			flame->destscale = player->mo->scale;
-			P_SetScale(flame, player->mo->scale);
+			P_SetScale(flame, player->mo->scale, true);
 			if (!(player->mo->flags2 & MF2_OBJECTFLIP) != !(player->powers[pw_gravityboots])) // take gravity boots into account
 				flame->flags2 |= MF2_OBJECTFLIP;
 			flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP);
@@ -7927,8 +7910,7 @@ void P_ElementalFire(player_t *player, boolean cropcircle)
 			P_SetTarget(&flame->target, player->mo);
 			flame->angle = travelangle;
 			flame->fuse = TICRATE*6;
-			flame->destscale = player->mo->scale;
-			P_SetScale(flame, player->mo->scale);
+			P_SetScale(flame, player->mo->scale, true);
 			if (!(player->mo->flags2 & MF2_OBJECTFLIP) != !(player->powers[pw_gravityboots])) // take gravity boots into account
 				flame->flags2 |= MF2_OBJECTFLIP;
 			flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP);
@@ -7976,8 +7958,7 @@ void P_SpawnSkidDust(player_t *player, fixed_t radius, boolean sound)
 	}
 	particle->tics = 10;
 
-	particle->destscale = (2*mo->scale)/3;
-	P_SetScale(particle, particle->destscale);
+	P_SetScale(particle, (2*mo->scale)/3, true);
 	P_SetObjectMomZ(particle, FRACUNIT, false);
 
 	if (mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) // overrides fire version
@@ -8566,8 +8547,7 @@ void P_MovePlayer(player_t *player)
 				water->flags2 |= MF2_OBJECTFLIP;
 				water->eflags |= MFE_VERTICALFLIP;
 			}
-			water->destscale = player->mo->scale;
-			P_SetScale(water, player->mo->scale);
+			P_SetScale(water, player->mo->scale, true);
 		}
 	}
 
@@ -10999,8 +10979,7 @@ static void P_SpawnSparks(mobj_t *mo, angle_t maindir)
 	spark->momz = mo->momz + r3;
 
 	P_Thrust(spark, R_PointToAngle2(mo->x, mo->y, spark->x, spark->y), 8*FRACUNIT);
-	P_SetScale(spark, FRACUNIT/4);
-	spark->destscale = spark->scale;
+	P_SetScale(spark, FRACUNIT/4, true);
 	spark->fuse = TICRATE/3;
 }
 
@@ -11472,8 +11451,9 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
 	tails->threshold = player->mo->z;
 	tails->movecount = player->panim;
 	tails->angle = horizangle;
-	P_SetScale(tails, player->mo->scale);
+	P_SetScale(tails, player->mo->scale, false);
 	tails->destscale = player->mo->destscale;
+	tails->old_scale = player->mo->old_scale;
 	tails->radius = player->mo->radius;
 	tails->height = player->mo->height;
 	zoffs = FixedMul(zoffs, tails->scale);
@@ -11564,7 +11544,9 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
 				y = mo->y + radiusY + FixedMul(offsetH, factorY);
 				z = mo->z + heightoffset + offsetV;
 				bubble = P_SpawnMobj(x, y, z, MT_SMALLBUBBLE);
-				bubble->scale = mo->scale >> 1;
+				P_SetScale(bubble, mo->scale/2, true);
+				bubble->destscale = mo->scale;
+				bubble->scalespeed = FixedMul(bubble->scalespeed, mo->scale);
 				P_SetTarget(&bubble->dontdrawforviewmobj, mo); // Hide the bubble in first-person
 			}
 
@@ -11585,7 +11567,7 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
 	if (stat == fume->info->spawnstate) // If currently inivisble, activate!
 	{
 		P_SetMobjState(fume, (stat = fume->info->seestate));
-		P_SetScale(fume, mo->scale);
+		P_SetScale(fume, mo->scale, false);
 		resetinterp = true;
 	}
 
@@ -11600,7 +11582,7 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
 		if (dashmode == DASHMODE_THRESHOLD && dashmode > (tic_t)fume->movecount) // If just about to enter dashmode, play the startup animation again
 		{
 			P_SetMobjState(fume, (stat = fume->info->seestate));
-			P_SetScale(fume, mo->scale << 1);
+			P_SetScale(fume, 2*mo->scale, true);
 		}
 		fume->flags2 = (fume->flags2 & ~MF2_DONTDRAW) | (mo->flags2 & MF2_DONTDRAW);
 		fume->destscale = (mo->scale + FixedDiv(player->speed, player->normalspeed)) / (underwater ? 6 : 3);
diff --git a/src/r_fps.c b/src/r_fps.c
index 83fd0eec15f4c9fd0f41fa60104be022b9b4c7eb..0773f228d6c8b6fdf266aff91f4f25e07080fee1 100644
--- a/src/r_fps.c
+++ b/src/r_fps.c
@@ -817,6 +817,10 @@ void R_ResetMobjInterpolationState(mobj_t *mobj)
 	mobj->old_roll2 = mobj->old_roll;
 	mobj->old_spriteroll2 = mobj->old_spriteroll;
 	mobj->old_scale2 = mobj->old_scale;
+	mobj->old_spritexscale2 = mobj->old_spritexscale;
+	mobj->old_spriteyscale2 = mobj->old_spriteyscale;
+	mobj->old_spritexoffset2 = mobj->old_spritexoffset;
+	mobj->old_spriteyoffset2 = mobj->old_spriteyoffset;
 	mobj->old_x = mobj->x;
 	mobj->old_y = mobj->y;
 	mobj->old_z = mobj->z;
@@ -853,6 +857,10 @@ void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj)
 	mobj->old_pitch2 = mobj->old_pitch;
 	mobj->old_roll2 = mobj->old_roll;
 	mobj->old_spriteroll2 = mobj->old_spriteroll;
+	mobj->old_spritexscale2 = mobj->old_spritexscale;
+	mobj->old_spriteyscale2 = mobj->old_spriteyscale;
+	mobj->old_spritexoffset2 = mobj->old_spritexoffset;
+	mobj->old_spriteyoffset2 = mobj->old_spriteyoffset;
 	mobj->old_x = mobj->x;
 	mobj->old_y = mobj->y;
 	mobj->old_z = mobj->z;
diff --git a/src/r_skins.c b/src/r_skins.c
index 6b4aeefe1726e46ee3f169540d5e87ad15dc271e..2029b4effb7184339f8ea2a906f28d0604447320 100644
--- a/src/r_skins.c
+++ b/src/r_skins.c
@@ -376,7 +376,7 @@ static void SetSkin(player_t *player, INT32 skinnum)
 		player->mo->skin = skin;
 		if (newcolor)
 			player->mo->color = newcolor;
-		P_SetScale(player->mo, player->mo->scale);
+		P_SetScale(player->mo, player->mo->scale, false);
 		player->mo->radius = radius;
 
 		P_SetMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames