diff --git a/src/deh_tables.c b/src/deh_tables.c
index cfc98f631e9d475f403e104425eae189949157bf..73da7313aac24580cd0c1e1ab8aad6e7abe7deec 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -224,6 +224,8 @@ actionpointer_t actionpointers[] =
 	{{A_SetObjectFlags2},        "A_SETOBJECTFLAGS2"},
 	{{A_RandomState},            "A_RANDOMSTATE"},
 	{{A_RandomStateRange},       "A_RANDOMSTATERANGE"},
+	{{A_StateRangeByAngle},      "A_STATERANGEBYANGLE"},
+	{{A_StateRangeByParameter},  "A_STATERANGEBYPARAMETER"},
 	{{A_DualAction},             "A_DUALACTION"},
 	{{A_RemoteAction},           "A_REMOTEACTION"},
 	{{A_ToggleFlameJet},         "A_TOGGLEFLAMEJET"},
diff --git a/src/doomdef.h b/src/doomdef.h
index 7e7e355990d422a8a6ecc86f54f49a17902ea66b..a5ee79cd3c95b1a3d96e6b93ba2de5b93946f49b 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -124,7 +124,7 @@ extern char logfilename[1024];
 /* A mod name to further distinguish versions. */
 #define SRB2APPLICATION "SRB2"
 
-//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
+#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
 #ifdef DEVELOP
 #define VERSIONSTRING "Development EXE"
 #define VERSIONSTRING_RC "Development EXE" "\0"
@@ -150,7 +150,7 @@ extern char logfilename[1024];
 
 // Does this version require an added patch file?
 // Comment or uncomment this as necessary.
-#define USE_PATCH_DTA
+//#define USE_PATCH_DTA
 
 // Enforce a limit of loaded WAD files.
 //#define ENFORCE_WAD_LIMIT
diff --git a/src/info.h b/src/info.h
index 031a08b4316a00d135cf45a45827ff117181373e..a0e1416067563b089322c163aba99e5cf28c42b3 100644
--- a/src/info.h
+++ b/src/info.h
@@ -177,6 +177,8 @@ enum actionnum
 	A_SETOBJECTFLAGS2,
 	A_RANDOMSTATE,
 	A_RANDOMSTATERANGE,
+	A_STATERANGEBYANGLE,
+	A_STATERANGEBYPARAMETER,
 	A_DUALACTION,
 	A_REMOTEACTION,
 	A_TOGGLEFLAMEJET,
@@ -443,6 +445,8 @@ void A_SetObjectFlags();
 void A_SetObjectFlags2();
 void A_RandomState();
 void A_RandomStateRange();
+void A_StateRangeByAngle();
+void A_StateRangeByParameter();
 void A_DualAction();
 void A_RemoteAction();
 void A_ToggleFlameJet();
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 9d51aced50899c8574997fa1d18b187db9e20371..c7b3673d6816f405d2848d249b20a13c17a6773f 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -200,6 +200,8 @@ void A_SetObjectFlags(mobj_t *actor);
 void A_SetObjectFlags2(mobj_t *actor);
 void A_RandomState(mobj_t *actor);
 void A_RandomStateRange(mobj_t *actor);
+void A_StateRangeByAngle(mobj_t *actor);
+void A_StateRangeByParameter(mobj_t *actor);
 void A_DualAction(mobj_t *actor);
 void A_RemoteAction(mobj_t *actor);
 void A_ToggleFlameJet(mobj_t *actor);
@@ -8292,7 +8294,7 @@ void A_Boss3ShockThink(mobj_t *actor)
 			snew->angle = (actor->angle + snext->angle) >> 1;
 			P_SetTarget(&snew->target, actor->target);
 			snew->fuse = actor->fuse;
-			
+
 			P_SetScale(snew, actor->scale);
 			snew->destscale = actor->destscale;
 			snew->scalespeed = actor->scalespeed;
@@ -9290,6 +9292,49 @@ void A_RandomStateRange(mobj_t *actor)
 	P_SetMobjState(actor, P_RandomRange(locvar1, locvar2));
 }
 
+// Function: A_StateRangeByAngle
+//
+// Description: Chooses a state within the range supplied, depending on the actor's angle.
+//
+// var1 = Minimum state number to use.
+// var2 = Maximum state number to use. The difference will act as a modulo operator.
+//
+void A_StateRangeByAngle(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+	if (LUA_CallAction(A_STATERANGEBYANGLE, actor))
+		return;
+
+	if (locvar2 - locvar1 < 0)
+		return; // invalid range
+
+	P_SetMobjState(actor, locvar1 + (AngleFixed(actor->angle)>>FRACBITS % (1 + locvar2 - locvar1)));
+}
+
+// Function: A_StateRangeByParameter
+//
+// Description: Chooses a state within the range supplied, depending on the actor's parameter/extrainfo value.
+//
+// var1 = Minimum state number to use.
+// var2 = Maximum state number to use. The difference will act as a modulo operator.
+//
+void A_StateRangeByParameter(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+	UINT8 parameter = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0);
+
+	if (LUA_CallAction(A_STATERANGEBYANGLE, actor))
+		return;
+
+	if (locvar2 - locvar1 < 0)
+		return; // invalid range
+
+	P_SetMobjState(actor, locvar1 + (parameter % (1 + locvar2 - locvar1)));
+}
+
 // Function: A_DualAction
 //
 // Description: Calls two actions. Be careful, if you reference the same state this action is called from, you can create an infinite loop.