diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index cad27f52c199d17e86c750b0069ebc4f4c9e267d..4448aaae042732fb6a52cf99236486b2e5656019 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -611,11 +611,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
 
 	rsp->health = LONG(players[i].mo->health);
 	rsp->angle = (angle_t)LONG(players[i].mo->angle);
-#ifdef ROTSPRITE
 	rsp->rollangle = (angle_t)LONG(players[i].mo->rollangle);
-#else
-	rsp->rollangle = 0;
-#endif
 	rsp->x = LONG(players[i].mo->x);
 	rsp->y = LONG(players[i].mo->y);
 	rsp->z = LONG(players[i].mo->z);
@@ -766,9 +762,7 @@ static void resynch_read_player(resynch_pak *rsp)
 	//At this point, the player should have a body, whether they were respawned or not.
 	P_UnsetThingPosition(players[i].mo);
 	players[i].mo->angle = (angle_t)LONG(rsp->angle);
-#ifdef ROTSPRITE
 	players[i].mo->rollangle = (angle_t)LONG(rsp->rollangle);
-#endif
 	players[i].mo->eflags = (UINT16)SHORT(rsp->eflags);
 	players[i].mo->flags = LONG(rsp->flags);
 	players[i].mo->flags2 = LONG(rsp->flags2);
diff --git a/src/dehacked.c b/src/dehacked.c
index 2c123e010cc4afecdb67c3816de49b13ba3a230c..b77939c2a678daf50696969910e2a95dc0e9312b 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -875,14 +875,12 @@ static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame)
 			strupr(word);
 			value = atoi(word2); // used for numerical settings
 
-#ifdef ROTSPRITE
 			if (fastcmp(word, "XPIVOT"))
 				sprinfo->pivot[frame].x = value;
 			else if (fastcmp(word, "YPIVOT"))
 				sprinfo->pivot[frame].y = value;
 			else if (fastcmp(word, "ROTAXIS"))
 				sprinfo->pivot[frame].rotaxis = value;
-#endif
 			else
 			{
 				f->curpos = lastline;
@@ -2910,11 +2908,9 @@ static actionpointer_t actionpointers[] =
 	{{A_SpawnObjectRelative},    "A_SPAWNOBJECTRELATIVE"},
 	{{A_ChangeAngleRelative},    "A_CHANGEANGLERELATIVE"},
 	{{A_ChangeAngleAbsolute},    "A_CHANGEANGLEABSOLUTE"},
-#ifdef ROTSPRITE
 	{{A_RollAngle},              "A_ROLLANGLE"},
 	{{A_ChangeRollAngleRelative},"A_CHANGEROLLANGLERELATIVE"},
 	{{A_ChangeRollAngleAbsolute},"A_CHANGEROLLANGLEABSOLUTE"},
-#endif
 	{{A_PlaySound},              "A_PLAYSOUND"},
 	{{A_FindTarget},             "A_FINDTARGET"},
 	{{A_FindTracer},             "A_FINDTRACER"},
@@ -9714,12 +9710,10 @@ struct {
 	{"DI_SOUTHEAST",DI_SOUTHEAST},
 	{"NUMDIRS",NUMDIRS},
 
-#ifdef ROTSPRITE
 	// Sprite rotation axis (rotaxis_t)
 	{"ROTAXIS_X",ROTAXIS_X},
 	{"ROTAXIS_Y",ROTAXIS_Y},
 	{"ROTAXIS_Z",ROTAXIS_Z},
-#endif
 
 	// Buttons (ticcmd_t)
 	{"BT_WEAPONMASK",BT_WEAPONMASK}, //our first four bits.
diff --git a/src/doomdef.h b/src/doomdef.h
index 0da1a1fedc3b3deacdf84ead5f6f1a1441cba957..8253f1a06266f23fed3fe97fd08ab34b88b0ce14 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -626,7 +626,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 
 /// Sprite rotation
 #define ROTSPRITE
-#define ROTANGLES 24	// Needs to be a divisor of 360 (45, 60, 90, 120...)
+#define ROTANGLES 72 // Needs to be a divisor of 360 (45, 60, 90, 120...)
 #define ROTANGDIFF (360 / ROTANGLES)
 
 /// PNG support
diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h
index 5f2d907bdee607d0b74051bad5f99baf5d0da823..95882b03eb93bb57fc429a12c648fdd8f5167c7b 100644
--- a/src/hardware/hw_defs.h
+++ b/src/hardware/hw_defs.h
@@ -115,13 +115,11 @@ typedef struct
 	FLOAT       fovxangle, fovyangle;
 	UINT8       splitscreen;
 	boolean     flip;            // screenflip
-#ifdef ROTSPRITE
 	boolean     roll;
 	SINT8       rollflip;
 	FLOAT       rollangle; // done to not override USE_FTRANSFORM_ANGLEZ
 	UINT8       rotaxis;
 	FLOAT       centerx, centery;
-#endif
 #ifdef USE_FTRANSFORM_MIRROR
 	boolean     mirror;          // SRB2Kart: Encore Mode
 #endif
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 630c1e181df8d6055284569606841af5c71123a8..3800b6ad98ff9b89af7ee38a7c328a87abcbf580 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1148,10 +1148,8 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
 		const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !(spr->mobj->frame & FF_VERTICALFLIP));
 		spritedef_t *sprdef;
 		spriteframe_t *sprframe;
-#ifdef ROTSPRITE
 		spriteinfo_t *sprinfo;
 		angle_t ang;
-#endif
 		INT32 mod;
 		float finalscale;
 
@@ -1175,16 +1173,12 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
 		{
 			md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins];
 			md2->skin = (skin_t*)spr->mobj->skin-skins;
-#ifdef ROTSPRITE
 			sprinfo = &((skin_t *)spr->mobj->skin)->sprinfo[spr->mobj->sprite2];
-#endif
 		}
 		else
 		{
 			md2 = &md2_models[spr->mobj->sprite];
-#ifdef ROTSPRITE
 			sprinfo = &spriteinfo[spr->mobj->sprite];
-#endif
 		}
 
 		if (md2->error)
@@ -1384,9 +1378,8 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
 			p.angley = FIXED_TO_FLOAT(anglef);
 		}
 
-#ifdef ROTSPRITE
 		p.rollangle = 0.0f;
-		p.rollflip = 0;
+		p.rollflip = 1;
 		p.rotaxis = 0;
 		if (spr->mobj->rollangle)
 		{
@@ -1409,7 +1402,6 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
 			else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
 				p.rollflip = -1;
 		}
-#endif
 
 		p.anglex = 0.0f;
 
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 129bf5678497aae3d4833fc3f0bed113d164be6c..97b3b98be576753f7b815ce3e49d7c3f825e319e 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -2076,7 +2076,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
 	pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
 	pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f);
 
-#ifdef ROTSPRITE
 	if (pos->roll)
 	{
 		float roll = (1.0f * pos->rollflip);
@@ -2089,7 +2088,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
 			pglRotatef(pos->rollangle, roll, 0.0f, 0.0f);
 		pglTranslatef(-pos->centerx, -pos->centery, 0);
 	}
-#endif
 
 	pglScalef(scalex, scaley, scalez);
 
diff --git a/src/info.h b/src/info.h
index 26fb1738ded63abfe1ba0edc08e696f05c192849..261abbac5f9da5812becad7f7a3ddcea35670635 100644
--- a/src/info.h
+++ b/src/info.h
@@ -155,11 +155,9 @@ void A_SpawnObjectAbsolute();
 void A_SpawnObjectRelative();
 void A_ChangeAngleRelative();
 void A_ChangeAngleAbsolute();
-#ifdef ROTSPRITE
 void A_RollAngle();
 void A_ChangeRollAngleRelative();
 void A_ChangeRollAngleAbsolute();
-#endif
 void A_PlaySound();
 void A_FindTarget();
 void A_FindTracer();
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 20eaa20489e538a531b688970a63bcd5811e83b7..695e9367e57d2fb972e48f833bae160d94f71744 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -147,10 +147,8 @@ static const struct {
 	{META_MOBJINFO,     "mobjinfo_t"},
 	{META_SFXINFO,      "sfxinfo_t"},
 	{META_SPRITEINFO,   "spriteinfo_t"},
-#ifdef ROTSPRITE
 	{META_PIVOTLIST,    "spriteframepivot_t[]"},
 	{META_FRAMEPIVOT,   "spriteframepivot_t"},
-#endif
 
 	{META_MOBJ,         "mobj_t"},
 	{META_MAPTHING,     "mapthing_t"},
diff --git a/src/lua_infolib.c b/src/lua_infolib.c
index b617a7a14d5885c45ddcac5a22c854733991680d..7a2465ef770ad2c36fde2805cb585360bf20d007 100644
--- a/src/lua_infolib.c
+++ b/src/lua_infolib.c
@@ -266,7 +266,6 @@ static int lib_getSpriteInfo(lua_State *L)
 #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to spriteinfo[] (%s)", e);
 #define TYPEERROR(f, t1, t2) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t1), lua_typename(L, t2)))
 
-#ifdef ROTSPRITE
 static int PopPivotSubTable(spriteframepivot_t *pivot, lua_State *L, int stk, int idx)
 {
 	int okcool = 0;
@@ -360,7 +359,6 @@ static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk)
 
 	return 0;
 }
-#endif
 
 static int lib_setSpriteInfo(lua_State *L)
 {
@@ -393,14 +391,11 @@ static int lib_setSpriteInfo(lua_State *L)
 		if (lua_isnumber(L, 2))
 		{
 			i = lua_tointeger(L, 2);
-#ifndef ROTSPRITE
 			i++; // shift index in case of missing rotsprite support
-#endif
 		}
 		else
 			str = luaL_checkstring(L, 2);
 
-#ifdef ROTSPRITE
 		if (i == 1 || (str && fastcmp(str, "pivot")))
 		{
 			// pivot[] is a table
@@ -409,7 +404,6 @@ static int lib_setSpriteInfo(lua_State *L)
 			else
 				FIELDERROR("pivot", va("%s expected, got %s", lua_typename(L, LUA_TTABLE), luaL_typename(L, -1)))
 		}
-#endif
 
 		lua_pop(L, 1);
 	}
@@ -434,7 +428,6 @@ static int spriteinfo_get(lua_State *L)
 
 	I_Assert(sprinfo != NULL);
 
-#ifdef ROTSPRITE
 	// push spriteframepivot_t userdata
 	if (fastcmp(field, "pivot"))
 	{
@@ -448,7 +441,6 @@ static int spriteinfo_get(lua_State *L)
 		return 1;
 	}
 	else
-#endif
 		return luaL_error(L, LUA_QL("spriteinfo_t") " has no field named " LUA_QS, field);
 
 	return 0;
@@ -473,6 +465,7 @@ static int spriteinfo_set(lua_State *L)
 #ifdef ROTSPRITE
 	if (sprites != NULL)
 		R_FreeSingleRotSprite(&sprites[sprinfo-spriteinfo]);
+#endif
 
 	if (fastcmp(field, "pivot"))
 	{
@@ -488,7 +481,6 @@ static int spriteinfo_set(lua_State *L)
 		}
 	}
 	else
-#endif
 		return luaL_error(L, va("Field %s does not exist in spriteinfo_t", field));
 
 	return 0;
@@ -506,7 +498,6 @@ static int spriteinfo_num(lua_State *L)
 }
 
 // framepivot_t
-#ifdef ROTSPRITE
 static int pivotlist_get(lua_State *L)
 {
 	void **userdata;
@@ -616,7 +607,6 @@ static int framepivot_num(lua_State *L)
 	lua_pushinteger(L, 2);
 	return 1;
 }
-#endif
 
 ////////////////
 // STATE INFO //
@@ -1538,7 +1528,6 @@ int LUA_InfoLib(lua_State *L)
 		lua_setfield(L, -2, "__len");
 	lua_pop(L, 1);
 
-#ifdef ROTSPRITE
 	luaL_newmetatable(L, META_PIVOTLIST);
 		lua_pushcfunction(L, pivotlist_get);
 		lua_setfield(L, -2, "__index");
@@ -1560,7 +1549,6 @@ int LUA_InfoLib(lua_State *L)
 		lua_pushcfunction(L, framepivot_num);
 		lua_setfield(L, -2, "__len");
 	lua_pop(L, 1);
-#endif
 
 	lua_newuserdata(L, 0);
 		lua_createtable(L, 0, 2);
diff --git a/src/lua_libs.h b/src/lua_libs.h
index 104a1e51c0c4338c3ec64e9196180dd5a4f5876a..6a908d03dbc7069990198f3fa3d940e36bf77177 100644
--- a/src/lua_libs.h
+++ b/src/lua_libs.h
@@ -23,10 +23,8 @@ extern lua_State *gL;
 #define META_MOBJINFO "MOBJINFO_T*"
 #define META_SFXINFO "SFXINFO_T*"
 #define META_SPRITEINFO "SPRITEINFO_T*"
-#ifdef ROTSPRITE
 #define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
 #define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"
-#endif
 
 #define META_MOBJ "MOBJ_T*"
 #define META_MAPTHING "MAPTHING_T*"
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 49f93d29cd4f5180eccf784b5ce01af56795db8e..22248775153b5afd4ce21c61656fc3f3b73a8a50 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -32,9 +32,7 @@ enum mobj_e {
 	mobj_snext,
 	mobj_sprev,
 	mobj_angle,
-#ifdef ROTSPRITE
 	mobj_rollangle,
-#endif
 	mobj_sprite,
 	mobj_frame,
 	mobj_sprite2,
@@ -101,9 +99,7 @@ static const char *const mobj_opt[] = {
 	"snext",
 	"sprev",
 	"angle",
-#ifdef ROTSPRITE
 	"rollangle",
-#endif
 	"sprite",
 	"frame",
 	"sprite2",
@@ -205,11 +201,9 @@ static int mobj_get(lua_State *L)
 	case mobj_angle:
 		lua_pushangle(L, mo->angle);
 		break;
-#ifdef ROTSPRITE
 	case mobj_rollangle:
 		lua_pushangle(L, mo->rollangle);
 		break;
-#endif
 	case mobj_sprite:
 		lua_pushinteger(L, mo->sprite);
 		break;
@@ -462,11 +456,9 @@ static int mobj_set(lua_State *L)
 		else if (mo->player == &players[secondarydisplayplayer])
 			localangle2 = mo->angle;
 		break;
-#ifdef ROTSPRITE
 	case mobj_rollangle:
 		mo->rollangle = luaL_checkangle(L, 3);
 		break;
-#endif
 	case mobj_sprite:
 		mo->sprite = luaL_checkinteger(L, 3);
 		break;
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 43ce161e600a6d5c2fc32d57057ca34c90671d24..f15ad86ae2cbbdccd2acaf02f6c15745b9cacde7 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -181,11 +181,9 @@ void A_SpawnObjectAbsolute(mobj_t *actor);
 void A_SpawnObjectRelative(mobj_t *actor);
 void A_ChangeAngleRelative(mobj_t *actor);
 void A_ChangeAngleAbsolute(mobj_t *actor);
-#ifdef ROTSPRITE
 void A_RollAngle(mobj_t *actor);
 void A_ChangeRollAngleRelative(mobj_t *actor);
 void A_ChangeRollAngleAbsolute(mobj_t *actor);
-#endif // ROTSPRITE
 void A_PlaySound(mobj_t *actor);
 void A_FindTarget(mobj_t *actor);
 void A_FindTracer(mobj_t *actor);
@@ -8627,7 +8625,6 @@ void A_ChangeAngleAbsolute(mobj_t *actor)
 	actor->angle = FixedAngle(P_RandomRange(amin, amax));
 }
 
-#ifdef ROTSPRITE
 // Function: A_RollAngle
 //
 // Description: Changes the roll angle.
@@ -8663,16 +8660,10 @@ void A_RollAngle(mobj_t *actor)
 //
 void A_ChangeRollAngleRelative(mobj_t *actor)
 {
-	// Oh god, the old code /sucked/. Changed this and the absolute version to get a random range using amin and amax instead of
-	//  getting a random angle from the _entire_ spectrum and then clipping. While we're at it, do the angle conversion to the result
-	//  rather than the ranges, so <0 and >360 work as possible values. -Red
 	INT32 locvar1 = var1;
 	INT32 locvar2 = var2;
-	//angle_t angle = (P_RandomByte()+1)<<24;
 	const fixed_t amin = locvar1*FRACUNIT;
 	const fixed_t amax = locvar2*FRACUNIT;
-	//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
-	//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
 #ifdef HAVE_BLUA
 	if (LUA_CallAction("A_ChangeRollAngleRelative", actor))
 		return;
@@ -8682,11 +8673,6 @@ void A_ChangeRollAngleRelative(mobj_t *actor)
 	if (amin > amax)
 		I_Error("A_ChangeRollAngleRelative: var1 is greater than var2");
 #endif
-/*
-	if (angle < amin)
-		angle = amin;
-	if (angle > amax)
-		angle = amax;*/
 
 	actor->rollangle += FixedAngle(P_RandomRange(amin, amax));
 }
@@ -8702,11 +8688,8 @@ void A_ChangeRollAngleAbsolute(mobj_t *actor)
 {
 	INT32 locvar1 = var1;
 	INT32 locvar2 = var2;
-	//angle_t angle = (P_RandomByte()+1)<<24;
 	const fixed_t amin = locvar1*FRACUNIT;
 	const fixed_t amax = locvar2*FRACUNIT;
-	//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
-	//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
 #ifdef HAVE_BLUA
 	if (LUA_CallAction("A_ChangeRollAngleAbsolute", actor))
 		return;
@@ -8716,15 +8699,9 @@ void A_ChangeRollAngleAbsolute(mobj_t *actor)
 	if (amin > amax)
 		I_Error("A_ChangeRollAngleAbsolute: var1 is greater than var2");
 #endif
-/*
-	if (angle < amin)
-		angle = amin;
-	if (angle > amax)
-		angle = amax;*/
 
 	actor->rollangle = FixedAngle(P_RandomRange(amin, amax));
 }
-#endif // ROTSPRITE
 
 // Function: A_PlaySound
 //
diff --git a/src/p_inter.c b/src/p_inter.c
index 3d5e32268db99608fb928e5d963a2503b47250f6..56a76b15c559da2797c301f9fab75c0ee3adadce 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -3005,9 +3005,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
 		P_SetPlayerMobjState(target, S_PLAY_NIGHTS_STUN);
 		S_StartSound(target, sfx_nghurt);
 
-#ifdef ROTSPRITE
 		player->mo->rollangle = 0;
-#endif
 
 		if (oldnightstime > 10*TICRATE
 			&& player->nightstime < 10*TICRATE)
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 78955d48c3c1a790989cba737724d445534a027f..75bc174a523b2be156dc9d94520b33c99fe59667 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -9763,15 +9763,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
 		P_DragonbomberThink(mobj);
 		break;
 	case MT_MINUS:
-#ifdef ROTSPRITE
-	{
 		if (P_IsObjectOnGround(mobj))
 			mobj->rollangle = 0;
 		else
 			mobj->rollangle = R_PointToAngle2(0, 0, mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1));
-	}
-#endif
-	break;
+		break;
 	case MT_SPINFIRE:
 		if (mobj->flags & MF_NOGRAVITY)
 		{
diff --git a/src/p_mobj.h b/src/p_mobj.h
index a272003c1d40db48e658d372e66e29ef8a710b64..92160d9e2d70f4634d90d47feed67cfa5940b1a9 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -279,9 +279,7 @@ typedef struct mobj_s
 
 	// More drawing info: to determine current sprite.
 	angle_t angle;  // orientation
-#ifdef ROTSPRITE
 	angle_t rollangle;
-#endif
 	spritenum_t sprite; // used to find patch_t and flip value
 	UINT32 frame; // frame number, plus bits see p_pspr.h
 	UINT8 sprite2; // player sprites
@@ -402,9 +400,7 @@ typedef struct precipmobj_s
 
 	// More drawing info: to determine current sprite.
 	angle_t angle;  // orientation
-#ifdef ROTSPRITE
 	angle_t rollangle;
-#endif
 	spritenum_t sprite; // used to find patch_t and flip value
 	UINT32 frame; // frame number, plus bits see p_pspr.h
 	UINT8 sprite2; // player sprites
diff --git a/src/p_saveg.c b/src/p_saveg.c
index f96368d0e3af3f504b0b316423d0e201bc195546..85efacf8852195302cd1023ceff75733f4cc04bc 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1252,9 +1252,7 @@ typedef enum
 	MD2_SLOPE        = 1<<11,
 #endif
 	MD2_COLORIZED    = 1<<12,
-#ifdef ROTSPRITE
 	MD2_ROLLANGLE    = 1<<13,
-#endif
 } mobj_diff2_t;
 
 typedef enum
@@ -1474,10 +1472,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 #endif
 	if (mobj->colorized)
 		diff2 |= MD2_COLORIZED;
-#ifdef ROTSPRITE
 	if (mobj->rollangle)
 		diff2 |= MD2_ROLLANGLE;
-#endif
 	if (diff2 != 0)
 		diff |= MD_MORE;
 
@@ -1642,10 +1638,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 #endif
 	if (diff2 & MD2_COLORIZED)
 		WRITEUINT8(save_p, mobj->colorized);
-#ifdef ROTSPRITE
 	if (diff2 & MD2_ROLLANGLE)
 		WRITEANGLE(save_p, mobj->rollangle);
-#endif
 
 	WRITEUINT32(save_p, mobj->mobjnum);
 }
@@ -2722,12 +2716,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
 #endif
 	if (diff2 & MD2_COLORIZED)
 		mobj->colorized = READUINT8(save_p);
-#ifdef ROTSPRITE
 	if (diff2 & MD2_ROLLANGLE)
 		mobj->rollangle = READANGLE(save_p);
-	else
-		mobj->rollangle = 0;
-#endif
 
 	if (diff & MD_REDFLAG)
 	{
diff --git a/src/p_user.c b/src/p_user.c
index 5b0140032a66ea9b610e1ea9eb0ff6b6bb106873..996faccd3f473c0319536ba4b0631335db11b3b1 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -638,9 +638,7 @@ static void P_DeNightserizePlayer(player_t *player)
 	player->marebonuslap = 0;
 	player->flyangle = 0;
 	player->anotherflyangle = 0;
-#ifdef ROTSPRITE
 	player->mo->rollangle = 0;
-#endif
 
 	P_SetTarget(&player->mo->target, NULL);
 	P_SetTarget(&player->axis1, P_SetTarget(&player->axis2, NULL));
@@ -768,9 +766,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 	player->secondjump = 0;
 	player->flyangle = 0;
 	player->anotherflyangle = 0;
-#ifdef ROTSPRITE
 	player->mo->rollangle = 0;
-#endif
 
 	player->powers[pw_shield] = SH_NONE;
 	player->powers[pw_super] = 0;
@@ -6820,7 +6816,6 @@ static void P_DoNiGHTSCapsule(player_t *player)
 			P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
 	}
 
-#ifdef ROTSPRITE
 	if (!(player->charflags & SF_NONIGHTSROTATION))
 	{
 		if ((player->mo->state == &states[S_PLAY_NIGHTS_PULL])
@@ -6829,7 +6824,6 @@ static void P_DoNiGHTSCapsule(player_t *player)
 		else
 			player->mo->rollangle = 0;
 	}
-#endif
 
 	if (G_IsSpecialStage(gamemap))
 	{ // In special stages, share rings. Everyone gives up theirs to the capsule player always, because we can't have any individualism here!
@@ -7092,9 +7086,7 @@ static void P_NiGHTSMovement(player_t *player)
 	INT32 i;
 	statenum_t flystate;
 	UINT16 visangle;
-#ifdef ROTSPRITE
 	angle_t rollangle = 0;
-#endif
 
 	player->pflags &= ~PF_DRILLING;
 
@@ -7279,9 +7271,7 @@ static void P_NiGHTSMovement(player_t *player)
 		&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
 	{
 		player->mo->momx = player->mo->momy = player->mo->momz = 0;
-#ifdef ROTSPRITE
 		player->mo->rollangle = 0;
-#endif
 		return;
 	}
 
@@ -7607,7 +7597,6 @@ static void P_NiGHTSMovement(player_t *player)
 			flystate += (visangle*2); // S_PLAY_NIGHTS_FLY0-C - the *2 is to skip over drill states
 #endif
 		}
-#ifdef ROTSPRITE
 		else
 		{
 			angle_t a = R_PointToAngle(player->mo->x, player->mo->y) - player->mo->angle;
@@ -7625,18 +7614,15 @@ static void P_NiGHTSMovement(player_t *player)
 
 			rollangle = FixedAngle(visangle<<FRACBITS);
 		}
-#endif
 	}
 
 	if (player->mo->state != &states[flystate])
 		P_SetPlayerMobjState(player->mo, flystate);
 
-#ifdef ROTSPRITE
 	if (player->charflags & SF_NONIGHTSROTATION)
 		player->mo->rollangle = 0;
 	else
 		player->mo->rollangle = rollangle;
-#endif
 
 	if (player == &players[consoleplayer])
 		localangle = player->mo->angle;
diff --git a/src/r_patch.c b/src/r_patch.c
index d4bfa9cbda29f84a07b234d91d13324a14979875..69d5ad1a2a9301ec02e167a1dd354f494243488e 100644
--- a/src/r_patch.c
+++ b/src/r_patch.c
@@ -789,11 +789,9 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info)
 	size_t sprinfoTokenLength;
 	char *frameChar = NULL;
 	UINT8 frameFrame = 0xFF;
-#ifdef ROTSPRITE
 	INT16 frameXPivot = 0;
 	INT16 frameYPivot = 0;
 	rotaxis_t frameRotAxis = 0;
-#endif
 
 	// Sprite identifier
 	sprinfoToken = M_GetToken(NULL);
@@ -828,7 +826,6 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info)
 			}
 			while (strcmp(sprinfoToken,"}")!=0)
 			{
-#ifdef ROTSPRITE
 				if (stricmp(sprinfoToken, "XPIVOT")==0)
 				{
 					Z_Free(sprinfoToken);
@@ -852,7 +849,6 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info)
 					else if ((stricmp(sprinfoToken, "Z")==0) || (stricmp(sprinfoToken, "ZAXIS")==0) || (stricmp(sprinfoToken, "YAW")==0))
 						frameRotAxis = ROTAXIS_Z;
 				}
-#endif
 				Z_Free(sprinfoToken);
 
 				sprinfoToken = M_GetToken(NULL);
@@ -866,11 +862,9 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info)
 	}
 
 	// set fields
-#ifdef ROTSPRITE
 	info->pivot[frameFrame].x = frameXPivot;
 	info->pivot[frameFrame].y = frameYPivot;
 	info->pivot[frameFrame].rotaxis = frameRotAxis;
-#endif
 }
 
 //
@@ -1093,15 +1087,41 @@ void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps)
 	for (i = 0; i < numlumps; i++, lumpinfo++)
 	{
 		name = lumpinfo->name;
-		// load SPRTINFO lumps
-		if (!stricmp(name, "SPRTINFO"))
+		// Load SPRTINFO and SPR_ lumps as SpriteInfo
+		if (!memcmp(name, "SPRTINFO", 8) || !memcmp(name, "SPR_", 4))
 			R_ParseSPRTINFOLump(wadnum, i);
-		// load SPR_ lumps (as DEHACKED lump)
-		else if (!memcmp(name, "SPR_", 4))
-			DEH_LoadDehackedLumpPwad(wadnum, i, false);
 	}
 }
 
+static UINT16 GetPatchPixel(patch_t *patch, INT32 x, INT32 y, boolean flip)
+{
+	fixed_t ofs;
+	column_t *column;
+	UINT8 *source;
+
+	if (x >= 0 && x < SHORT(patch->width))
+	{
+		INT32 topdelta, prevdelta = -1;
+		column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[flip ? (patch->width-1-x) : x]));
+		while (column->topdelta != 0xff)
+		{
+			topdelta = column->topdelta;
+			if (topdelta <= prevdelta)
+				topdelta += prevdelta;
+			prevdelta = topdelta;
+			source = (UINT8 *)(column) + 3;
+			for (ofs = 0; ofs < column->length; ofs++)
+			{
+				if ((topdelta + ofs) == y)
+					return source[ofs];
+			}
+			column = (column_t *)((UINT8 *)column + column->length + 4);
+		}
+	}
+
+	return 0xFF00;
+}
+
 #ifdef ROTSPRITE
 //
 // R_CacheRotSprite
@@ -1114,8 +1134,8 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
 	INT32 angle;
 	patch_t *patch;
 	patch_t *newpatch;
-	UINT16 *rawsrc, *rawdst;
-	size_t size, size2;
+	UINT16 *rawdst;
+	size_t size;
 	INT32 bflip = (flip != 0x00);
 
 #define SPRITE_XCENTER (leftoffset)
@@ -1160,18 +1180,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
 			leftoffset = width - leftoffset;
 		}
 
-		// Draw the sprite to a temporary buffer.
-		size = (width*height);
-		rawsrc = Z_Malloc(size * sizeof(UINT16), PU_STATIC, NULL);
-
-		// can't memset here
-		for (i = 0; i < size; i++)
-			rawsrc[i] = 0xFF00;
-
-		R_PatchToFlat_16bpp(patch, rawsrc, bflip);
-
-		// Don't cache angle = 0
-		for (angle = 1; angle < ROTANGLES; angle++)
+		for (angle = 0; angle < ROTANGLES; angle++)
 		{
 			INT32 newwidth, newheight;
 
@@ -1237,17 +1246,15 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
 #undef BOUNDARYADJUST
 			}
 
-			size2 = (newwidth * newheight);
-			if (!size2)
-				size2 = size;
-
-			rawdst = Z_Malloc(size2 * sizeof(UINT16), PU_STATIC, NULL);
+			// Draw the rotated sprite to a temporary buffer.
+			size = (newwidth * newheight);
+			if (!size)
+				size = (width * height);
 
-			// can't memset here
-			for (i = 0; i < size2; i++)
+			rawdst = Z_Malloc(size * sizeof(UINT16), PU_STATIC, NULL);
+			for (i = 0; i < size; i++)
 				rawdst[i] = 0xFF00;
 
-			// Draw the rotated sprite to a temporary buffer.
 			for (dy = 0; dy < newheight; dy++)
 			{
 				for (dx = 0; dx < newwidth; dx++)
@@ -1259,7 +1266,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
 					sx >>= FRACBITS;
 					sy >>= FRACBITS;
 					if (sx >= 0 && sy >= 0 && sx < width && sy < height)
-						rawdst[(dy*newwidth)+dx] = rawsrc[(sy*width)+sx];
+						rawdst[(dy*newwidth)+dx] = GetPatchPixel(patch, sx, sy, bflip);
 				}
 			}
 
@@ -1296,7 +1303,6 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
 		sprframe->rotsprite.cached[rot] = true;
 
 		// free image data
-		Z_Free(rawsrc);
 		Z_Free(patch);
 	}
 #undef SPRITE_XCENTER
diff --git a/src/r_patch.h b/src/r_patch.h
index 8a8ab5602bbebaa507a84cb129b82d5a35bac53d..c534debdb21c83f3b637d5f44e5161f00a9efad7 100644
--- a/src/r_patch.h
+++ b/src/r_patch.h
@@ -18,7 +18,6 @@
 #include "doomdef.h"
 
 // Structs
-#ifdef ROTSPRITE
 typedef enum
 {
 	ROTAXIS_X, // Roll (the default)
@@ -31,13 +30,10 @@ typedef struct
 	INT32 x, y;
 	rotaxis_t rotaxis;
 } spriteframepivot_t;
-#endif
 
 typedef struct
 {
-#ifdef ROTSPRITE
 	spriteframepivot_t pivot[64];
-#endif
 	boolean available;
 } spriteinfo_t;
 
diff --git a/src/r_things.c b/src/r_things.c
index aa2a73515adfd2d75d450e18b6d9d10c9b050f34..d29baa711b98fd8956df7a6f59b5602bfbc4a2ad 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -500,7 +500,7 @@ void R_InitSprites(void)
 {
 	size_t i;
 #ifdef ROTSPRITE
-	INT32 angle, realangle = 0;
+	INT32 angle, ra;
 	float fa;
 #endif
 
@@ -510,10 +510,12 @@ void R_InitSprites(void)
 #ifdef ROTSPRITE
 	for (angle = 0; angle < ROTANGLES; angle++)
 	{
-		fa = ANG2RAD(FixedAngle(realangle<<FRACBITS));
+		ra = (ROTANGDIFF * angle);
+		if (!ra)
+			ra = (ROTANGDIFF / 2) + 1;
+		fa = ANG2RAD(FixedAngle(ra<<FRACBITS));
 		cosang2rad[angle] = FLOAT_TO_FIXED(cos(-fa));
 		sinang2rad[angle] = FLOAT_TO_FIXED(sin(-fa));
-		realangle += ROTANGDIFF;
 	}
 #endif