diff --git a/src/p_enemy.c b/src/p_enemy.c
index 87aa5ff2f80e7f61fd092ab2fa4f1dedac9d3370..40aab9ec1c4bf337a894efa16cb6e84fd3c4968c 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -1406,7 +1406,7 @@ void A_StatueBurst(mobj_t *actor)
 	if (!locvar1 || !(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1)))
 		return;
 
-	new->angle = actor->angle;
+	P_InitAngle(new, actor->angle);
 	P_SetTarget(&new->target, actor->target);
 	if (locvar2)
 		P_SetMobjState(new, (statenum_t)locvar2);
@@ -2700,8 +2700,8 @@ void A_LobShot(mobj_t *actor)
 
 	P_SetTarget(&shot->target, actor); // where it came from
 
-	shot->angle = an = actor->angle;
-	an >>= ANGLETOFINESHIFT;
+	P_InitAngle(shot, actor->angle);
+	an = actor->angle >> ANGLETOFINESHIFT;
 
 	dist = P_AproxDistance(actor->target->x - shot->x, actor->target->y - shot->y);
 
@@ -3067,7 +3067,7 @@ void A_Boss1Laser(mobj_t *actor)
 			S_StartSound(actor, mobjinfo[locvar1].seesound);
 
 		point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET);
-		point->angle = actor->angle;
+		P_InitAngle(point, actor->angle);
 		point->fuse = dur+1;
 		P_SetTarget(&point->target, actor->target);
 		P_SetTarget(&actor->target, point);
@@ -3077,7 +3077,7 @@ void A_Boss1Laser(mobj_t *actor)
 
 	point = P_SpawnMobj(x, y, z, locvar1);
 	P_SetTarget(&point->target, actor);
-	point->angle = actor->angle;
+	P_InitAngle(point, actor->angle);
 	speed = point->radius;
 	point->momz = FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT), speed);
 	point->momx = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(point->angle>>ANGLETOFINESHIFT), speed));
@@ -3086,7 +3086,7 @@ void A_Boss1Laser(mobj_t *actor)
 	for (i = 0; i < 256; i++)
 	{
 		mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type);
-		mo->angle = point->angle;
+		P_InitAngle(mo, point->angle);
 		mo->color = LASERCOLORS[((UINT8)(i + 3*dur) >> 2) % sizeof(LASERCOLORS)]; // codeing
 		P_UnsetThingPosition(mo);
 		mo->flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY;
@@ -3118,7 +3118,7 @@ void A_Boss1Laser(mobj_t *actor)
 	if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1 && dur & 1)
 	{
 		point = P_SpawnMobj(x, y, floorz, MT_EGGMOBILE_FIRE);
-		point->angle = actor->angle;
+		P_InitAngle(point, actor->angle);
 		point->destscale = actor->scale;
 		P_SetScale(point, point->destscale);
 		P_SetTarget(&point->target, actor);
@@ -3970,7 +3970,7 @@ bossjustdie:
 					P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<<FRACBITS),
 					P_ReturnThrustY(mo, mo->angle - ANGLE_90, 32<<FRACBITS),
 					32<<FRACBITS, MT_BOSSJUNK);
-				mo2->angle = mo->angle;
+				P_InitAngle(mo2, mo->angle);
 				P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale);
 				P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
 				P_SetMobjState(mo2, S_BOSSEGLZ1);
@@ -3979,7 +3979,7 @@ bossjustdie:
 					P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<<FRACBITS),
 					P_ReturnThrustY(mo, mo->angle + ANGLE_90, 32<<FRACBITS),
 					32<<FRACBITS, MT_BOSSJUNK);
-				mo2->angle = mo->angle;
+				P_InitAngle(mo2, mo->angle);
 				P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale);
 				P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
 				P_SetMobjState(mo2, S_BOSSEGLZ2);
@@ -3991,7 +3991,7 @@ bossjustdie:
 					P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<<FRACBITS),
 					P_ReturnThrustY(mo, mo->angle - ANGLE_90, 32<<FRACBITS),
 					32<<FRACBITS, MT_BOSSJUNK);
-				mo2->angle = mo->angle;
+				P_InitAngle(mo2, mo->angle);
 				P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale);
 				P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
 				P_SetMobjState(mo2, S_BOSSTANK1);
@@ -4000,7 +4000,7 @@ bossjustdie:
 					P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<<FRACBITS),
 					P_ReturnThrustY(mo, mo->angle + ANGLE_90, 32<<FRACBITS),
 					32<<FRACBITS, MT_BOSSJUNK);
-				mo2->angle = mo->angle;
+				P_InitAngle(mo2, mo->angle);
 				P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale);
 				P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
 				P_SetMobjState(mo2, S_BOSSTANK2);
@@ -4008,7 +4008,7 @@ bossjustdie:
 				mo2 = P_SpawnMobjFromMobj(mo, 0, 0,
 					mobjinfo[MT_EGGMOBILE2].height + (32<<FRACBITS),
 					MT_BOSSJUNK);
-				mo2->angle = mo->angle;
+				P_InitAngle(mo2, mo->angle);
 				P_SetObjectMomZ(mo2, 4*FRACUNIT, false);
 				mo2->momz += mo->momz;
 				P_SetMobjState(mo2, S_BOSSSPIGOT);
@@ -4017,7 +4017,7 @@ bossjustdie:
 		case MT_EGGMOBILE3:
 			{
 				mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSJUNK);
-				mo2->angle = mo->angle;
+				P_InitAngle(mo2, mo->angle);
 				P_SetMobjState(mo2, S_BOSSSEBH1);
 			}
 			break;
@@ -4091,7 +4091,8 @@ bossjustdie:
 					pole->tracer->flags |= MF_NOCLIPTHING;
 					P_SetScale(pole, (pole->destscale = 2*FRACUNIT));
 					P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT));
-					pole->angle = pole->tracer->angle = mo->tracer->angle;
+					P_InitAngle(pole, mo->tracer->angle);
+					P_InitAngle(pole->tracer, mo->tracer->angle);
 					pole->tracer->tracer->angle = pole->angle - ANGLE_90;
 					pole->momx = P_ReturnThrustX(pole, pole->angle, speed);
 					pole->momy = P_ReturnThrustY(pole, pole->angle, speed);
@@ -6254,7 +6255,7 @@ void A_RockSpawn(mobj_t *actor)
 
 	mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK);
 	P_SetMobjState(mo, mobjinfo[type].spawnstate);
-	mo->angle = R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y);
+	P_InitAngle(mo, R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y));
 
 	P_InstaThrust(mo, mo->angle, dist + randomoomph);
 	mo->momz = dist + randomoomph;
@@ -8312,7 +8313,7 @@ void A_Boss3ShockThink(mobj_t *actor)
 			snew->momx = (actor->momx + snext->momx) >> 1;
 			snew->momy = (actor->momy + snext->momy) >> 1;
 			snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed?
-			snew->angle = (actor->angle + snext->angle) >> 1;
+			P_InitAngle(snew, (actor->angle + snext->angle) >> 1);
 			P_SetTarget(&snew->target, actor->target);
 			snew->fuse = actor->fuse;
 
@@ -8468,7 +8469,7 @@ void A_SpawnObjectAbsolute(mobj_t *actor)
 	mo = P_SpawnMobj(x<<FRACBITS, y<<FRACBITS, z<<FRACBITS, type);
 
 	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
-	mo->angle = actor->angle;
+	P_InitAngle(mo, actor->angle);
 
 	if (actor->eflags & MFE_VERTICALFLIP)
 		mo->flags2 |= MF2_OBJECTFLIP;
@@ -8510,7 +8511,7 @@ void A_SpawnObjectRelative(mobj_t *actor)
 		(actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[type].height) - FixedMul(z<<FRACBITS, actor->scale)) : (actor->z + FixedMul(z<<FRACBITS, actor->scale)), type);
 
 	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
-	mo->angle = actor->angle;
+	P_InitAngle(mo, actor->angle);
 
 	if (actor->eflags & MFE_VERTICALFLIP)
 		mo->flags2 |= MF2_OBJECTFLIP;
@@ -9220,7 +9221,7 @@ void A_BossJetFume(mobj_t *actor)
 		P_SetScale(filler, filler->destscale);
 		if (actor->eflags & MFE_VERTICALFLIP)
 			filler->flags2 |= MF2_OBJECTFLIP;
-		filler->angle = actor->angle - ANGLE_180;
+		P_InitAngle(filler, actor->angle - ANGLE_180);
 
 		P_SetTarget(&actor->tracer, filler);
 	}*/
@@ -10982,7 +10983,7 @@ void A_TrapShot(mobj_t *actor)
 		S_StartSound(missile, missile->info->seesound);
 
 	P_SetTarget(&missile->target, actor);
-	missile->angle = actor->angle;
+	P_InitAngle(missile, actor->angle);
 
 	speed = FixedMul(missile->info->speed, missile->scale);
 
@@ -11561,7 +11562,7 @@ void A_BrakLobShot(mobj_t *actor)
 		S_StartSound(shot, shot->info->seesound);
 	P_SetTarget(&shot->target, actor); // where it came from
 
-	shot->angle = actor->angle;
+	P_InitAngle(shot, actor->angle);
 
 	// Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle.
 	shot->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(shot->angle >> ANGLETOFINESHIFT));
@@ -11628,7 +11629,7 @@ void A_NapalmScatter(mobj_t *actor)
 		mo = P_SpawnMobj(actor->x, actor->y, actor->z, typeOfShot);
 		P_SetTarget(&mo->target, actor->target); // Transfer target so Brak doesn't hit himself like an idiot
 
-		mo->angle = fa << ANGLETOFINESHIFT;
+		P_InitAngle(mo, fa << ANGLETOFINESHIFT);
 		mo->momx = FixedMul(FINECOSINE(fa),vx);
 		mo->momy = FixedMul(FINESINE(fa),vx);
 		mo->momz = vy;
@@ -11652,7 +11653,7 @@ void A_SpawnFreshCopy(mobj_t *actor)
 
 	newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type);
 	newObject->flags2 = actor->flags2 & MF2_AMBUSH;
-	newObject->angle = actor->angle;
+	P_InitAngle(newObject, actor->angle);
 	newObject->color = actor->color;
 	P_SetTarget(&newObject->target, actor->target);
 	P_SetTarget(&newObject->tracer, actor->tracer);
@@ -11686,7 +11687,7 @@ mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz
 	}
 
 	flicky = P_SpawnMobjFromMobj(actor, offsx, offsy, 0, flickytype);
-	flicky->angle = actor->angle;
+	P_InitAngle(flicky, actor->angle);
 
 	if (flickytype == MT_SEED)
 		flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2;
@@ -11836,7 +11837,7 @@ void A_FlickyCenter(mobj_t *actor)
 		else if (actor->flags & MF_SLIDEME) // aimless
 		{
 			actor->tracer->fuse = 0; // less than 2*TICRATE means move aimlessly.
-			actor->tracer->angle = P_RandomKey(180)*ANG2;
+			P_InitAngle(actor->tracer, P_RandomKey(180)*ANG2);
 		}
 		else //orbit
 			actor->tracer->fuse = FRACUNIT;
@@ -12532,7 +12533,7 @@ void A_ConnectToGround(mobj_t *actor)
 	{
 		work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1);
 		if (work)
-			work->angle = ang;
+			P_InitAngle(work, ang);
 		ang += ANGLE_90;
 		workz += workh;
 	}
@@ -12578,7 +12579,7 @@ void A_SpawnParticleRelative(mobj_t *actor)
 		(actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<<FRACBITS, actor->scale)) : (actor->z + FixedMul(z<<FRACBITS, actor->scale)), MT_PARTICLE);
 
 	// Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn
-	mo->angle = actor->angle;
+	P_InitAngle(mo, actor->angle);
 
 	if (actor->eflags & MFE_VERTICALFLIP)
 		mo->flags2 |= MF2_OBJECTFLIP;
@@ -13325,7 +13326,7 @@ void A_Boss5MakeJunk(mobj_t *actor)
 			broked->fuse = TICRATE;
 		else
 			broked->fuse = (((locvar2 & 1) ? 4 : 2)*TICRATE)/3;
-		broked->angle = ang;
+		P_InitAngle(broked, ang);
 		P_InstaThrust(broked, ang, ((locvar2 & 2) ? 8 : 5)*actor->scale);
 		P_SetObjectMomZ(broked, (((locvar2) ? 4 : 0) + P_RandomRange(2, 5))<<FRACBITS, false);
 		if (locvar1 > 0)
@@ -13404,7 +13405,7 @@ static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fi
 			mobjtype
 			);
 
-		dust->angle = ang*i + ANGLE_90;
+		P_InitAngle(dust, ang*i + ANGLE_90);
 		P_SetScale(dust, FixedMul(initscale, scale));
 		dust->destscale = FixedMul(4*FRACUNIT + P_RandomFixed(), scale);
 		dust->scalespeed = scale/24;
@@ -13758,7 +13759,7 @@ static mobj_t *P_TrainSeg(mobj_t *src, fixed_t x, fixed_t y, fixed_t z, angle_t
 	s->fuse = 16*TICRATE;
 	s->sprite = spr;
 	s->frame = frame|FF_PAPERSPRITE;
-	s->angle = ang;
+	P_InitAngle(s, ang);
 	P_Thrust(s, src->angle, 7*FRACUNIT);
 	return s;
 }
@@ -14130,7 +14131,7 @@ void A_SaloonDoorSpawn(mobj_t *actor)
 
 	// One door...
 	if (!(door = P_SpawnMobjFromMobj(actor, c, s, 0, locvar1))) return;
-	door->angle = ang + ANGLE_180;
+	P_InitAngle(door, ang + ANGLE_180);
 	door->extravalue1 = AngleFixed(door->angle); // Origin angle
 	door->extravalue2 = 0; // Angular speed
 	P_SetTarget(&door->tracer, actor); // Origin door
@@ -14138,7 +14139,7 @@ void A_SaloonDoorSpawn(mobj_t *actor)
 
 	// ...two door!
 	if (!(door = P_SpawnMobjFromMobj(actor, -c, -s, 0, locvar1))) return;
-	door->angle = ang;
+	P_InitAngle(door, ang);
 	door->extravalue1 = AngleFixed(door->angle); // Origin angle
 	door->extravalue2 = 0; // Angular speed
 	P_SetTarget(&door->tracer, actor); // Origin door
@@ -14334,7 +14335,7 @@ void A_SpawnPterabytes(mobj_t *actor)
 		c = FINECOSINE(fa);
 		s = FINESINE(fa);
 		waypoint = P_SpawnMobjFromMobj(actor, FixedMul(c, rad), FixedMul(s, rad), 0, MT_PTERABYTEWAYPOINT);
-		waypoint->angle = ang + ANGLE_90;
+		P_InitAngle(waypoint, ang + ANGLE_90);
 		P_SetTarget(&waypoint->tracer, actor);
 		ptera = P_SpawnMobjFromMobj(waypoint, 0, 0, 0, MT_PTERABYTE);
 		ptera->angle = waypoint->angle;
@@ -14514,7 +14515,7 @@ void A_DragonbomberSpawn(mobj_t *actor)
 		segment = P_SpawnMobjFromMobj(mo, x, y, 0, MT_DRAGONTAIL);
 		P_SetTarget(&segment->target, mo);
 		P_SetTarget(&mo->tracer, segment);
-		segment->angle = mo->angle;
+		P_InitAngle(segment, mo->angle);
 		mo = segment;
 	}
 	for (i = 0; i < 2; i++) // spawn wings
diff --git a/src/p_inter.c b/src/p_inter.c
index 582cdb0d091df4fc6b0ee9d5698babcff6acd9fb..56ef235780af2a865ba675fdcaae22ea1a16eb9c 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -2749,7 +2749,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 					mo->angle = FixedAngle((P_RandomKey(36)*10)<<FRACBITS);
 
 					mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSJUNK);
-					mo2->angle = mo->angle;
+					P_InitAngle(mo2, mo->angle);
 					P_SetMobjState(mo2, S_BOSSSEBH2);
 
 					if (++i == 2) // we've already removed 2 of these, let's stop now
@@ -2852,7 +2852,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 			chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);\
 			P_SetMobjState(chunk, target->info->xdeathstate);\
 			chunk->health = 0;\
-			chunk->angle = angtweak;\
+			P_InitAngle(chunk, angtweak);\
 			P_UnsetThingPosition(chunk);\
 			chunk->flags = MF_NOCLIP;\
 			chunk->x += xmov;\
@@ -2874,7 +2874,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 		chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);
 		P_SetMobjState(chunk, target->info->deathstate);
 		chunk->health = 0;
-		chunk->angle = ang + ANGLE_180;
+		P_InitAngle(chunk, ang + ANGLE_180);
 		P_UnsetThingPosition(chunk);
 		chunk->flags = MF_NOCLIP;
 		chunk->x -= xoffs;
@@ -2920,7 +2920,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 			chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);\
 			P_SetMobjState(chunk, target->info->xdeathstate);\
 			chunk->health = 0;\
-			chunk->angle = target->angle;\
+			P_InitAngle(chunk, target->angle);\
 			P_UnsetThingPosition(chunk);\
 			chunk->flags = MF_NOCLIP;\
 			chunk->x += xmov - forwardxoffs;\
@@ -2946,7 +2946,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 
 		P_SetMobjState(chunk, target->info->deathstate);
 		chunk->health = 0;
-		chunk->angle = target->angle;
+		P_InitAngle(chunk, target->angle);
 		P_UnsetThingPosition(chunk);
 		chunk->flags = MF_NOCLIP;
 		chunk->x += forwardxoffs - xoffs;
diff --git a/src/p_local.h b/src/p_local.h
index ba8cbe166aa1df73a96536c9d813565255a1841b..ec7e65b71176af6c772c5b5da6907b178cd05168 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -415,6 +415,9 @@ boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
 boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
 boolean P_Move(mobj_t *actor, fixed_t speed);
 boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z);
+void P_InitAngle(mobj_t *thing, angle_t newValue);
+void P_InitPitch(mobj_t *thing, angle_t newValue);
+void P_InitRoll(mobj_t *thing, angle_t newValue);
 void P_SlideMove(mobj_t *mo);
 void P_BounceMove(mobj_t *mo);
 boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
diff --git a/src/p_map.c b/src/p_map.c
index 145f9bbe9c2bb97866ab61e349ed64eda6ddfefd..1f02123d5b5bc07e69b5143f7cbf0d55a8b7bc21 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -108,6 +108,30 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
 	return true;
 }
 
+//
+// P_InitAngle - Change an object's angle, including interp values.
+//
+void P_InitAngle(mobj_t *thing, angle_t newValue)
+{
+	thing->angle = thing->old_angle = newValue;
+}
+
+//
+// P_InitPitch - Change an object's pitch, including interp values.
+//
+void P_InitPitch(mobj_t *thing, angle_t newValue)
+{
+	thing->pitch = thing->old_pitch = newValue;
+}
+
+//
+// P_InitRoll - Change an object's roll, including interp values.
+//
+void P_InitRoll(mobj_t *thing, angle_t newValue)
+{
+	thing->roll = thing->old_roll = newValue;
+}
+
 // =========================================================================
 //                       MOVEMENT ITERATOR FUNCTIONS
 // =========================================================================
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 90707eae5cb04cbf0b4bd1d7eeebcf2fc6d3d4b7..57af599cf2b66c0b20a8ec92028cdc2870afa724 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -903,6 +903,8 @@ void P_ResetInterpolationState(mobj_t *mobj)
 	mobj->old_y = mobj->y;
 	mobj->old_z = mobj->z;
 	mobj->old_angle = mobj->angle;
+	mobj->old_pitch = mobj->pitch;
+	mobj->old_roll = mobj->roll;
 
 	if (mobj->player)
 	{
@@ -6372,7 +6374,7 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb
 		mobj->z -= mobj->height>>1;
 
 		// change angle
-		mobj->angle = R_PointToAngle2(mobj->x, mobj->y, x, y);
+		P_InitAngle(mobj, R_PointToAngle2(mobj->x, mobj->y, x, y));
 
 		// change slope
 		dist = P_AproxDistance(P_AproxDistance(x - mobj->x, y - mobj->y), z - mobj->z);
@@ -7256,7 +7258,7 @@ static void P_FlameJetSceneryThink(mobj_t *mobj)
 	flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME);
 	P_SetMobjState(flame, S_FLAMEJETFLAME4);
 
-	flame->angle = mobj->angle;
+	P_InitAngle(flame, mobj->angle);
 
 	if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side
 		flame->momz = mobj->fuse << (FRACBITS - 2);
@@ -10730,7 +10732,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 		case MT_CRUSHSTACEAN:
 			{
 				mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CRUSHCLAW);
-				bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);;
+				P_InitAngle(bigmeatyclaw, mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270));
 				P_SetTarget(&mobj->tracer, bigmeatyclaw);
 				P_SetTarget(&bigmeatyclaw->tracer, mobj);
 				mobj->reactiontime >>= 1;
@@ -10739,7 +10741,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 		case MT_BANPYURA:
 			{
 				mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_BANPSPRING);
-				bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);;
+				P_InitAngle(bigmeatyclaw, mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270));
 				P_SetTarget(&mobj->tracer, bigmeatyclaw);
 				P_SetTarget(&bigmeatyclaw->tracer, mobj);
 				mobj->reactiontime >>= 1;
@@ -10861,7 +10863,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			break;
 		case MT_MINECARTEND:
 			P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID));
-			mobj->tracer->angle = mobj->angle + ANGLE_90;
+			P_InitAngle(mobj->tracer, mobj->angle + ANGLE_90);
 			break;
 		case MT_TORCHFLOWER:
 			{
@@ -11492,7 +11494,7 @@ void P_SpawnPlayer(INT32 playernum)
 	mobj = P_SpawnMobj(0, 0, 0, MT_PLAYER);
 	(mobj->player = p)->mo = mobj;
 
-	mobj->angle = 0;
+	P_InitAngle(mobj, 0);
 
 	// set color translations for player sprites
 	mobj->color = p->skincolor;
@@ -11560,6 +11562,12 @@ void P_AfterPlayerSpawn(INT32 playernum)
 	player_t *p = &players[playernum];
 	mobj_t *mobj = p->mo;
 
+	// Update interpolation
+	mobj->old_x = mobj->x;
+	mobj->old_y = mobj->y;
+	mobj->old_z = mobj->z;
+	mobj->old_angle = mobj->angle;
+
 	P_SetPlayerAngle(p, mobj->angle);
 
 	p->viewheight = 41*p->height/48;
@@ -12345,7 +12353,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle)
 	spawnee->friction = mroll;\
 	spawnee->movefactor = mwidthset;\
 	spawnee->movecount = dist;\
-	spawnee->angle = myaw;\
+	P_InitAngle(spawnee, myaw);\
 	spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\
 	spawnee->flags2 |= (mflags2apply|moreflags2);\
 	spawnee->eflags |= meflagsapply;\
@@ -12663,29 +12671,29 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong)
 	statenum_t rollerstate = strong ? S_REDBOOSTERROLLER : S_YELLOWBOOSTERROLLER;
 
 	mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG);
-	seg->angle = angle - ANGLE_90;
+	P_InitAngle(seg, angle - ANGLE_90);
 	P_SetMobjState(seg, facestate);
 	seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG);
-	seg->angle = angle + ANGLE_90;
+	P_InitAngle(seg, angle + ANGLE_90);
 	P_SetMobjState(seg, facestate);
 	seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG);
-	seg->angle = angle;
+	P_InitAngle(seg, angle);
 	P_SetMobjState(seg, leftstate);
 	seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG);
-	seg->angle = angle;
+	P_InitAngle(seg, angle);
 	P_SetMobjState(seg, rightstate);
 
 	seg = P_SpawnMobjFromMobj(mobj, 13*(x1 + x2), 13*(y1 + y2), 0, MT_BOOSTERROLLER);
-	seg->angle = angle;
+	P_InitAngle(seg, angle);
 	P_SetMobjState(seg, rollerstate);
 	seg = P_SpawnMobjFromMobj(mobj, 13*(x1 - x2), 13*(y1 - y2), 0, MT_BOOSTERROLLER);
-	seg->angle = angle;
+	P_InitAngle(seg, angle);
 	P_SetMobjState(seg, rollerstate);
 	seg = P_SpawnMobjFromMobj(mobj, -13*(x1 + x2), -13*(y1 + y2), 0, MT_BOOSTERROLLER);
-	seg->angle = angle;
+	P_InitAngle(seg, angle);
 	P_SetMobjState(seg, rollerstate);
 	seg = P_SpawnMobjFromMobj(mobj, -13*(x1 - x2), -13*(y1 - y2), 0, MT_BOOSTERROLLER);
-	seg->angle = angle;
+	P_InitAngle(seg, angle);
 	P_SetMobjState(seg, rollerstate);
 
 	return true;
@@ -12901,9 +12909,9 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 	case MT_THZTREE:
 	{ // Spawn the branches
 		angle_t mobjangle = FixedAngle((mthing->angle % 113) << FRACBITS);
-		P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h;
-		P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h;
-		P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270;
+		P_InitAngle(P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_22h);
+		P_InitAngle(P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_157h);
+		P_InitAngle(P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_270);
 	}
 	break;
 	case MT_TUTORIALPLANT:
@@ -12929,10 +12937,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 	case MT_CEZPOLE2:
 	{ // Spawn the banner
 		angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS);
-		P_SpawnMobjFromMobj(mobj,
+		P_InitAngle(P_SpawnMobjFromMobj(mobj,
 			P_ReturnThrustX(mobj, mobjangle, 4 << FRACBITS),
 			P_ReturnThrustY(mobj, mobjangle, 4 << FRACBITS),
-			0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90;
+			0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2)), mobjangle + ANGLE_90);
 	}
 	break;
 	case MT_HHZTREE_TOP:
@@ -12941,7 +12949,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 		mobj_t* leaf;
 #define doleaf(x, y) \
 			leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\
-			leaf->angle = mobjangle;\
+			P_InitAngle(leaf, mobjangle);\
 			P_SetMobjState(leaf, leaf->info->seestate);\
 			mobjangle += ANGLE_90
 		doleaf(FRACUNIT, 0);
@@ -12982,7 +12990,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 			fixed_t xoffs = FINECOSINE(fa);
 			fixed_t yoffs = FINESINE(fa);
 			mobj_t* leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF);
-			leaf->angle = angle;
+			P_InitAngle(leaf, angle);
 			angle += ANGLE_45;
 		}
 		break;
@@ -13108,7 +13116,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 				mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius),
 				mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius),
 				mobj->z, MT_WALLSPIKEBASE);
-			base->angle = mobjangle + ANGLE_90;
+			P_InitAngle(base, mobjangle + ANGLE_90);
 			base->destscale = mobj->destscale;
 			P_SetScale(base, mobj->scale);
 			P_SetTarget(&base->target, mobj);
@@ -13236,10 +13244,12 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y,
 		return mobj;
 
 	if (doangle)
-		mobj->angle = FixedAngle(mthing->angle << FRACBITS);
+	{
+		P_InitAngle(mobj, FixedAngle(mthing->angle << FRACBITS));
+	}
 
-	mobj->pitch = FixedAngle(mthing->pitch << FRACBITS);
-	mobj->roll = FixedAngle(mthing->roll << FRACBITS);
+	P_InitPitch(mobj, FixedAngle(mthing->pitch << FRACBITS));
+	P_InitRoll(mobj, FixedAngle(mthing->roll << FRACBITS));
 
 	mthing->mobj = mobj;
 
@@ -13675,7 +13685,7 @@ mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type,
 	P_SetTarget(&th->target, source); // where it came from
 	an = R_PointToAngle2(x, y, dest->x, dest->y);
 
-	th->angle = an;
+	P_InitAngle(th, an);
 	an >>= ANGLETOFINESHIFT;
 	th->momx = FixedMul(speed, FINECOSINE(an));
 	th->momy = FixedMul(speed, FINESINE(an));
@@ -13737,7 +13747,7 @@ mobj_t *P_SpawnAlteredDirectionMissile(mobj_t *source, mobjtype_t type, fixed_t
 	P_SetTarget(&th->target, source->target); // where it came from
 	an = R_PointToAngle2(0, 0, source->momx, source->momy) + (ANG1*shiftingAngle);
 
-	th->angle = an;
+	P_InitAngle(th, an);
 	an >>= ANGLETOFINESHIFT;
 	th->momx = FixedMul(speed, FINECOSINE(an));
 	th->momy = FixedMul(speed, FINESINE(an));
@@ -13802,7 +13812,7 @@ mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za,
 	P_SetTarget(&th->target, source); // where it came from
 	an = R_PointToAngle2(x, y, xa, ya);
 
-	th->angle = an;
+	P_InitAngle(th, an);
 	an >>= ANGLETOFINESHIFT;
 	th->momx = FixedMul(speed, FINECOSINE(an));
 	th->momy = FixedMul(speed, FINESINE(an));
@@ -13881,7 +13891,7 @@ mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
 	else
 		an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
 
-	th->angle = an;
+	P_InitAngle(th, an);
 	an >>= ANGLETOFINESHIFT;
 	th->momx = FixedMul(speed, FINECOSINE(an));
 	th->momy = FixedMul(speed, FINESINE(an));
@@ -13971,7 +13981,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai
 	if (source->player && source->player->charability == CA_FLY)
 		speed = FixedMul(speed, 3*FRACUNIT/2);
 
-	th->angle = an;
+	P_InitAngle(th, an);
 	th->momx = FixedMul(speed, FINECOSINE(an>>ANGLETOFINESHIFT));
 	th->momy = FixedMul(speed, FINESINE(an>>ANGLETOFINESHIFT));
 
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 9975075a1c21ae1862b2c9d43239107f845efb67..371dc49dc67cbbd3e3b634f7133d5556e020c32a 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -287,7 +287,7 @@ typedef struct mobj_s
 
 	// More drawing info: to determine current sprite.
 	angle_t angle, pitch, roll; // orientation
-	angle_t old_angle;
+	angle_t old_angle, old_pitch, old_roll; // orientation interpolation
 	angle_t rollangle;
 	spritenum_t sprite; // used to find patch_t and flip value
 	UINT32 frame; // frame number, plus bits see p_pspr.h
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 99ec58bb97c74080ad171d40a65bbf804c25459c..46b509d19ce94e7c32f8e5174ef56453661c73ac 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -2758,19 +2758,19 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 	mobj->info = &mobjinfo[mobj->type];
 	if (diff & MD_POS)
 	{
-		mobj->x = READFIXED(save_p);
-		mobj->y = READFIXED(save_p);
-		mobj->angle = READANGLE(save_p);
-		mobj->pitch = READANGLE(save_p);
-		mobj->roll = READANGLE(save_p);
+		mobj->x = mobj->old_x = READFIXED(save_p);
+		mobj->y = mobj->old_y = READFIXED(save_p);
+		mobj->angle = mobj->old_angle = READANGLE(save_p);
+		mobj->pitch = mobj->old_pitch = READANGLE(save_p);
+		mobj->roll = mobj->old_roll = READANGLE(save_p);
 	}
 	else
 	{
-		mobj->x = mobj->spawnpoint->x << FRACBITS;
-		mobj->y = mobj->spawnpoint->y << FRACBITS;
-		mobj->angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT);
-		mobj->pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT);
-		mobj->roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT);
+		mobj->x = mobj->old_x = mobj->spawnpoint->x << FRACBITS;
+		mobj->y = mobj->old_y = mobj->spawnpoint->y << FRACBITS;
+		mobj->angle = mobj->old_angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT);
+		mobj->pitch = mobj->old_pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT);
+		mobj->roll = mobj->old_roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT);
 	}
 	if (diff & MD_MOM)
 	{
diff --git a/src/p_spec.c b/src/p_spec.c
index 6147a83920c19528dab8e14a978a3d26c77eca26..34dcd917dc0b58b2925399451bef47a95c6600e3 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3755,7 +3755,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 				if (mobj)
 				{
 					if (line->flags & ML_EFFECT1)
-						mobj->angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y);
+						P_InitAngle(mobj, R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y));
 					CONS_Debug(DBG_GAMELOGIC, "Linedef Type %d - Spawn Object: %d spawned at (%d, %d, %d)\n", line->special, mobj->type, mobj->x>>FRACBITS, mobj->y>>FRACBITS, mobj->z>>FRACBITS); //TODO: Convert mobj->type to a string somehow.
 				}
 				else
diff --git a/src/p_telept.c b/src/p_telept.c
index cbbd0ff6bcffc7b91db3a5d6c7323d55394a4b4c..cfd7be1e264517a3d4e1322c414e74a64b9e1943 100644
--- a/src/p_telept.c
+++ b/src/p_telept.c
@@ -101,7 +101,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
 		P_FlashPal(thing->player, PAL_MIXUP, 10);
 	}
 
-	thing->angle = angle;
+	P_InitAngle(thing, angle);
 
 	thing->momx = thing->momy = thing->momz = 0;
 
@@ -174,7 +174,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle
 			P_FlashPal(thing->player, PAL_MIXUP, 10);
 	}
 
-	thing->angle = angle;
+	P_InitAngle(thing, angle);
 
 	return true;
 }
diff --git a/src/p_user.c b/src/p_user.c
index 8e8194da0f064a329ca62f29279208efdc787a82..f047499d0ff22a10a12794b3d30b55bbd4a7383b 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -393,7 +393,7 @@ void P_GiveFinishFlags(player_t *player)
 		fixed_t xoffs = FINECOSINE(fa);
 		fixed_t yoffs = FINESINE(fa);
 		mobj_t* flag = P_SpawnMobjFromMobj(player->mo, xoffs, yoffs, 0, MT_FINISHFLAG);
-		flag->angle = angle;
+		P_InitAngle(flag, angle);
 		angle += FixedAngle(120*FRACUNIT);
 
 		P_SetTarget(&flag->target, player->mo);
diff --git a/src/r_fps.c b/src/r_fps.c
index 863e9613a40f56f790176150cdd55d494d32dd38..708add82097da1a90fcb0bde2211ffbdb17e7126 100644
--- a/src/r_fps.c
+++ b/src/r_fps.c
@@ -211,6 +211,9 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out)
 	{
 		out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac);
 	}
+
+	out->pitch = R_LerpAngle(mobj->old_pitch, mobj->pitch, frac);
+	out->roll = R_LerpAngle(mobj->old_roll, mobj->roll, frac);
 }
 
 void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out)
@@ -219,6 +222,8 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst
 	out->y = R_LerpFixed(mobj->old_y, mobj->y, frac);
 	out->z = R_LerpFixed(mobj->old_z, mobj->z, frac);
 	out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac);
+	out->pitch = 0;
+	out->roll = 0;
 }
 
 static void AddInterpolator(levelinterpolator_t* interpolator)
diff --git a/src/r_fps.h b/src/r_fps.h
index aa6213ae34d3ddbdbed4d205562de89fb3bcd235..1eb53b3469d41bcb1691fbcecc6bbbe9d5aa35e1 100644
--- a/src/r_fps.h
+++ b/src/r_fps.h
@@ -49,6 +49,8 @@ typedef struct {
 	fixed_t y;
 	fixed_t z;
 	angle_t angle;
+	angle_t pitch;
+	angle_t roll;
 } interpmobjstate_t;
 
 // Level interpolators