From 4ddfd0f46a26df2b349182197b4a16c7a0e4f3f8 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Tue, 30 Dec 2014 19:59:31 -0600
Subject: [PATCH 1/2] - Added 3 new properties and 3 functions to control them.
 - Rippers will rip through anything with an equivalent ripper level, or if
 their level is between or on the min and max ranges. - If no min or max is
 defined, it simply checks if the monster's ripper level is lower than the
 missiles. - Functions: A_SetRipperLevel(int level), A_SetRipMin(int min),
 A_SetRipMax(int max) - Properties: RipperLevel, RipLevelMin, and RipLevelMax.
 - RipperLevel: Applicable to monsters and projectiles. - RipLevelMin and
 RipLevelMax are only useful on monsters. - By default, all are 0.

---
 src/actor.h                          |  3 ++
 src/p_map.cpp                        | 12 +++++++-
 src/p_mobj.cpp                       |  7 +++++
 src/thingdef/thingdef_codeptr.cpp    | 42 ++++++++++++++++++++++++++++
 src/thingdef/thingdef_properties.cpp | 27 ++++++++++++++++++
 src/version.h                        |  2 +-
 wadsrc/static/actors/actor.txt       |  6 ++++
 7 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/src/actor.h b/src/actor.h
index 57736f43b..bc6e830f0 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -985,6 +985,9 @@ public:
 	FNameNoInit DeathType;
 	const PClass *TeleFogSourceType;
 	const PClass *TeleFogDestType;
+	int RipperLevel;
+	int RipLevelMin;
+	int RipLevelMax;
 
 	FState *SpawnState;
 	FState *SeeState;
diff --git a/src/p_map.cpp b/src/p_map.cpp
index aecead6ed..233cc50cd 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -1207,7 +1207,17 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
 		{
 			return true;
 		}
-		if (tm.DoRipping && !(thing->flags5 & MF5_DONTRIP))
+		// Rippers will rip through anything with an equivalent ripper level,
+		// or if the missile's ripper level is within the min/max range,
+		// or if there's no min/max range and the missile's ripper level is
+		// >= the monster's, then let 'er rip!
+		bool ripmin = (thing->RipLevelMin != 0) ? true : false;
+		bool ripmax = (thing->RipLevelMax != 0) ? true : false;
+		if ((tm.DoRipping && !(thing->flags5 & MF5_DONTRIP)) && 
+			((!(ripmin) && !(ripmax) && (thing->RipperLevel <= tm.thing->RipperLevel)) ||
+			((thing->RipperLevel == tm.thing->RipperLevel) ||
+			(thing->RipLevelMin <= tm.thing->RipperLevel) &&
+			(thing->RipLevelMax >= tm.thing->RipperLevel))))
 		{
 			if (!(tm.thing->flags6 & MF6_NOBOSSRIP) || !(thing->flags2 & MF2_BOSS))
 			{
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index dbce9e2ff..6a035933d 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -338,6 +338,13 @@ void AActor::Serialize (FArchive &arc)
 		arc << TeleFogSourceType
 			<< TeleFogDestType;
 	}
+	if (SaveVersion >= 4518)
+	{
+		arc << RipperLevel
+			<< RipLevelMin
+			<< RipLevelMax;
+	}
+
 	{
 		FString tagstr;
 		if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag;
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 50969ce85..54645d864 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -5613,3 +5613,45 @@ DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog)
 		self->TeleFogDestType = temp;
 	}
 }
+
+//===========================================================================
+//
+// A_SetRipperLevel(int level)
+//
+// Sets the ripper level/requirement of the calling actor.
+// Also sets the minimum and maximum levels to rip through.
+//===========================================================================
+DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipperLevel)
+{
+	ACTION_PARAM_START(1);
+	ACTION_PARAM_INT(level, 0);
+	self->RipperLevel = level;
+}
+
+//===========================================================================
+//
+// A_SetRipMin(int min)
+//
+// Sets the ripper level/requirement of the calling actor.
+// Also sets the minimum and maximum levels to rip through.
+//===========================================================================
+DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMin)
+{
+	ACTION_PARAM_START(1);
+	ACTION_PARAM_INT(min, 1);
+	self->RipLevelMin = min; 
+}
+
+//===========================================================================
+//
+// A_SetRipMin(int min)
+//
+// Sets the ripper level/requirement of the calling actor.
+// Also sets the minimum and maximum levels to rip through.
+//===========================================================================
+DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax)
+{
+	ACTION_PARAM_START(1);
+	ACTION_PARAM_INT(max, 1);
+	self->RipLevelMax = max;
+}
\ No newline at end of file
diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp
index b6a2937ae..a00ac62e1 100644
--- a/src/thingdef/thingdef_properties.cpp
+++ b/src/thingdef/thingdef_properties.cpp
@@ -1436,6 +1436,33 @@ DEFINE_PROPERTY(telefogdesttype, S, Actor)
 	else defaults->TeleFogDestType = FindClassTentative(str, "TeleportFog");
 }
 
+//==========================================================================
+//
+//==========================================================================
+DEFINE_PROPERTY(ripperlevel, I, Actor)
+{
+	PROP_INT_PARM(id, 0);
+	defaults->RipperLevel = id;
+}
+
+//==========================================================================
+//
+//==========================================================================
+DEFINE_PROPERTY(riplevelmin, I, Actor)
+{
+	PROP_INT_PARM(id, 0);
+	defaults->RipLevelMin = id;
+}
+
+//==========================================================================
+//
+//==========================================================================
+DEFINE_PROPERTY(riplevelmax, I, Actor)
+{
+	PROP_INT_PARM(id, 0);
+	defaults->RipLevelMax = id;
+}
+
 //==========================================================================
 //
 // Special inventory properties
diff --git a/src/version.h b/src/version.h
index 6863f0573..09b830438 100644
--- a/src/version.h
+++ b/src/version.h
@@ -76,7 +76,7 @@ const char *GetVersionString();
 
 // Use 4500 as the base git save version, since it's higher than the
 // SVN revision ever got.
-#define SAVEVER 4517
+#define SAVEVER 4518
 
 #define SAVEVERSTRINGIFY2(x) #x
 #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt
index 73a5e0e4d..c32ecb958 100644
--- a/wadsrc/static/actors/actor.txt
+++ b/wadsrc/static/actors/actor.txt
@@ -28,6 +28,9 @@ ACTOR Actor native //: Thinker
 	DeathType Normal
 	TeleFogSourceType "TeleportFog"
 	TeleFogDestType "TeleportFog"
+	RipperLevel 0
+	RipLevelMin 0
+	RipLevelMax 0
 
 	// Variables for the expression evaluator
 	// NOTE: fixed_t and angle_t are only used here to ensure proper conversion
@@ -321,6 +324,9 @@ ACTOR Actor native //: Thinker
 	action native A_TakeFromSiblings(class<Inventory> itemtype, int amount = 0);
 	action native A_SetTeleFog(name oldpos, name newpos);
 	action native A_SwapTeleFog();
+	action native A_SetRipperLevel(int level);
+	action native A_SetRipMin(int min);
+	action native A_SetRipMax(int max);
 
 	action native A_CheckSightOrRange(float distance, state label);
 	action native A_CheckRange(float distance, state label);

From c57cc91d7c062b7629abc8f7c4fdaa95086432bf Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@zdoom.fake>
Date: Wed, 31 Dec 2014 10:13:15 +0100
Subject: [PATCH 2/2] - cleaned up the RipLevel logic a bit to be less
 confusing.

---
 src/p_map.cpp                        | 27 ++++++++++++++++-----------
 src/thingdef/thingdef_properties.cpp | 12 ++++++++++++
 2 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/src/p_map.cpp b/src/p_map.cpp
index 233cc50cd..68d0b21f0 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -887,6 +887,20 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
 	return true;
 }
 
+
+//==========================================================================
+//
+// Isolated to keep the code readable and fix the logic
+//
+//==========================================================================
+
+static bool CheckRipLevel(AActor *victim, AActor *projectile)
+{
+	if (victim->RipLevelMin > 0 && projectile->RipperLevel < victim->RipLevelMin) return false;
+	if (victim->RipLevelMax > 0 && projectile->RipperLevel > victim->RipLevelMax) return false;
+	return true;
+}
+
 //==========================================================================
 //
 // PIT_CheckThing
@@ -1207,17 +1221,8 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
 		{
 			return true;
 		}
-		// Rippers will rip through anything with an equivalent ripper level,
-		// or if the missile's ripper level is within the min/max range,
-		// or if there's no min/max range and the missile's ripper level is
-		// >= the monster's, then let 'er rip!
-		bool ripmin = (thing->RipLevelMin != 0) ? true : false;
-		bool ripmax = (thing->RipLevelMax != 0) ? true : false;
-		if ((tm.DoRipping && !(thing->flags5 & MF5_DONTRIP)) && 
-			((!(ripmin) && !(ripmax) && (thing->RipperLevel <= tm.thing->RipperLevel)) ||
-			((thing->RipperLevel == tm.thing->RipperLevel) ||
-			(thing->RipLevelMin <= tm.thing->RipperLevel) &&
-			(thing->RipLevelMax >= tm.thing->RipperLevel))))
+
+		if ((tm.DoRipping && !(thing->flags5 & MF5_DONTRIP)) && CheckRipLevel(thing, tm.thing))
 		{
 			if (!(tm.thing->flags6 & MF6_NOBOSSRIP) || !(thing->flags2 & MF2_BOSS))
 			{
diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp
index a00ac62e1..677979276 100644
--- a/src/thingdef/thingdef_properties.cpp
+++ b/src/thingdef/thingdef_properties.cpp
@@ -1442,6 +1442,10 @@ DEFINE_PROPERTY(telefogdesttype, S, Actor)
 DEFINE_PROPERTY(ripperlevel, I, Actor)
 {
 	PROP_INT_PARM(id, 0);
+	if (id < 0)
+	{
+		I_Error ("RipperLevel must not be negative");
+	}
 	defaults->RipperLevel = id;
 }
 
@@ -1451,6 +1455,10 @@ DEFINE_PROPERTY(ripperlevel, I, Actor)
 DEFINE_PROPERTY(riplevelmin, I, Actor)
 {
 	PROP_INT_PARM(id, 0);
+	if (id < 0)
+	{
+		I_Error ("RipLevelMin must not be negative");
+	}
 	defaults->RipLevelMin = id;
 }
 
@@ -1460,6 +1468,10 @@ DEFINE_PROPERTY(riplevelmin, I, Actor)
 DEFINE_PROPERTY(riplevelmax, I, Actor)
 {
 	PROP_INT_PARM(id, 0);
+	if (id < 0)
+	{
+		I_Error ("RipLevelMax must not be negative");
+	}
 	defaults->RipLevelMax = id;
 }