From a8248433e95080d8bc2d94910ea6a49f14b2c596 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Sun, 1 May 2016 08:45:50 -0500
Subject: [PATCH 01/63] - Updated <pitch>/flat/roll/wall sprites submission to
 2.9+. (ZDoom compatibility submission. ) - FLATSPRITE: An actor becomes flat
 as if they were a decal on the floor. - PITCHFLATSPRITE: A flat sprite tilts
 up and down based on pitch. - WALLSPRITE: Similar to a Y billboarded sprite.
 The degree of the flattening is determined by the FlatAngle property. -
 ROLLSPRITE: The sprite of the actor is affected by the Roll property.

---
 src/actor.h                       |  5 ++++-
 src/p_mobj.cpp                    |  3 ++-
 src/thingdef/thingdef_codeptr.cpp | 22 ++++++++++++++++++++++
 src/thingdef/thingdef_data.cpp    |  5 +++++
 src/version.h                     |  4 ++--
 wadsrc/static/actors/actor.txt    |  1 +
 6 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/src/actor.h b/src/actor.h
index 0336c4185..1d1090c19 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -407,12 +407,14 @@ enum ActorRenderFlag
 	RF_SPRITETYPEMASK	= 0x7000,	// ---Different sprite types, not all implemented
 	RF_FACESPRITE		= 0x0000,	// Face sprite
 	RF_WALLSPRITE		= 0x1000,	// Wall sprite
-	RF_FLOORSPRITE		= 0x2000,	// Floor sprite
+	RF_FLATSPRITE		= 0x2000,	// Flat sprite
 	RF_VOXELSPRITE		= 0x3000,	// Voxel object
+	RF_PITCHFLATSPRITE	= 0x4000,	// [MC] Flat sprite that rotates around pitch (GZDoom only)
 	RF_INVISIBLE		= 0x8000,	// Don't bother drawing this actor
 
 	RF_FORCEYBILLBOARD		= 0x10000,	// [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting)
 	RF_FORCEXYBILLBOARD		= 0x20000,	// [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting)
+	RF_ROLLSPRITE		= 0x40000,	//[marrub]roll the sprite billboard
 };
 
 // This translucency value produces the closest match to Heretic's TINTTAB.
@@ -974,6 +976,7 @@ public:
 	DVector3		OldRenderPos;
 
 	DRotator		Angles;
+	DAngle			FlatAngle;
 	DVector3		Vel;
 	double			Speed;
 	double			FloatSpeed;
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index b7d887195..77e862028 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -262,7 +262,8 @@ void AActor::Serialize(FArchive &arc)
 		<< projectilepassheight
 		<< Vel
 		<< tics
-		<< state;
+		<< state
+		<< FlatAngle;
 	if (arc.IsStoring())
 	{
 		int dmg;
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 34a9cf02c..20848f478 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -6881,3 +6881,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection)
 	}
 	ACTION_RETURN_BOOL(true);
 }
+
+//===========================================================================
+//
+// A_SetFlatAngle
+//
+// Set actor's flat angle (in degrees). GZDoom only. Requires the 
+// (PITCH)FLATSPRITE flag to have any visible effect.
+//
+//===========================================================================
+DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFlatAngle)
+{
+	PARAM_ACTION_PROLOGUE;
+	PARAM_FLOAT_OPT(flatangle) { flatangle = 0; }
+	PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; }
+	
+	AActor *ref = COPY_AAPTR(self, ptr);
+	if (ref != NULL)
+	{
+		ref->FlatAngle = flatangle;
+	}
+	return 0;
+}
\ No newline at end of file
diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp
index efb7be0c2..8b245e828 100644
--- a/src/thingdef/thingdef_data.cpp
+++ b/src/thingdef/thingdef_data.cpp
@@ -265,6 +265,11 @@ static FFlagDef ActorFlagDefs[]=
 	DEFINE_FLAG(RF, INVISIBLE, AActor, renderflags),
 	DEFINE_FLAG(RF, FORCEYBILLBOARD, AActor, renderflags),
 	DEFINE_FLAG(RF, FORCEXYBILLBOARD, AActor, renderflags),
+	DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard 
+			// [fgsfds] Flat sprites
+	DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
+	DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
+	DEFINE_FLAG(RF, PITCHFLATSPRITE, AActor, renderflags),
 
 	// Bounce flags
 	DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
diff --git a/src/version.h b/src/version.h
index 21d05b3ed..68c7d0325 100644
--- a/src/version.h
+++ b/src/version.h
@@ -72,11 +72,11 @@ const char *GetVersionString();
 // SAVESIG should match SAVEVER.
 
 // MINSAVEVER is the minimum level snapshot version that can be loaded.
-#define MINSAVEVER	4545
+#define MINSAVEVER	4546
 
 // Use 4500 as the base git save version, since it's higher than the
 // SVN revision ever got.
-#define SAVEVER 4545
+#define SAVEVER 4546
 
 #define SAVEVERSTRINGIFY2(x) #x
 #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt
index 8b35be30d..f47a1d87a 100644
--- a/wadsrc/static/actors/actor.txt
+++ b/wadsrc/static/actors/actor.txt
@@ -325,6 +325,7 @@ ACTOR Actor native //: Thinker
 	native state A_CheckSightOrRange(float distance, state label, bool two_dimension = false);
 	native state A_CheckRange(float distance, state label, bool two_dimension = false);
 	action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
+	action native A_SetFlatAngle(float flatangle = 0, int ptr = AAPTR_DEFAULT);
 
 	native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0);
 	native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0);

From 9ba547e6e3c835b9555097b9956e91ae2996f06e Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Sun, 1 May 2016 11:38:20 -0500
Subject: [PATCH 02/63] Revert MINSAVEVER and added FlatAngle DECORATE property
 expression.

---
 src/namedef.h                  | 1 +
 src/p_mobj.cpp                 | 7 +++++--
 src/thingdef/thingdef_data.cpp | 1 +
 src/version.h                  | 2 +-
 4 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/namedef.h b/src/namedef.h
index 17fa9e291..622e5ed5f 100644
--- a/src/namedef.h
+++ b/src/namedef.h
@@ -300,6 +300,7 @@ xx(ATan2)
 xx(VectorAngle)
 xx(Alpha)
 xx(Angle)
+xx(FlatAngle)
 xx(Args)
 xx(CeilingZ)
 xx(FloorZ)
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 77e862028..5dbfd9651 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -262,8 +262,11 @@ void AActor::Serialize(FArchive &arc)
 		<< projectilepassheight
 		<< Vel
 		<< tics
-		<< state
-		<< FlatAngle;
+		<< state;
+	if (SaveVersion >= 4545)
+	{
+		arc << FlatAngle;
+	}
 	if (arc.IsStoring())
 	{
 		int dmg;
diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp
index 8b245e828..9669c78ab 100644
--- a/src/thingdef/thingdef_data.cpp
+++ b/src/thingdef/thingdef_data.cpp
@@ -627,6 +627,7 @@ void InitThingdef()
 	PType *array5 = NewArray(TypeSInt32, 5);
 	symt.AddSymbol(new PField(NAME_Alpha,		TypeFloat64,	VARF_Native, myoffsetof(AActor,Alpha)));
 	symt.AddSymbol(new PField(NAME_Angle,		TypeFloat64,	VARF_Native, myoffsetof(AActor,Angles.Yaw)));
+	symt.AddSymbol(new PField(NAME_FlatAngle,	TypeFloat64,	VARF_Native, myoffsetof(AActor,FlatAngle)));
 	symt.AddSymbol(new PField(NAME_Args,		array5,			VARF_Native, myoffsetof(AActor,args)));
 	symt.AddSymbol(new PField(NAME_CeilingZ,	TypeFloat64,	VARF_Native, myoffsetof(AActor,ceilingz)));
 	symt.AddSymbol(new PField(NAME_FloorZ,		TypeFloat64,	VARF_Native, myoffsetof(AActor,floorz)));
diff --git a/src/version.h b/src/version.h
index 68c7d0325..52b7ea0ba 100644
--- a/src/version.h
+++ b/src/version.h
@@ -72,7 +72,7 @@ const char *GetVersionString();
 // SAVESIG should match SAVEVER.
 
 // MINSAVEVER is the minimum level snapshot version that can be loaded.
-#define MINSAVEVER	4546
+#define MINSAVEVER	4545
 
 // Use 4500 as the base git save version, since it's higher than the
 // SVN revision ever got.

From 3ed95510545914d3e1408c8212f6f90067bf55b3 Mon Sep 17 00:00:00 2001
From: MajorCooke <MajorCooke@users.noreply.github.com>
Date: Sun, 1 May 2016 14:33:22 -0500
Subject: [PATCH 03/63] Fixed typo.

---
 src/p_mobj.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 5dbfd9651..e51a62856 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -263,7 +263,7 @@ void AActor::Serialize(FArchive &arc)
 		<< Vel
 		<< tics
 		<< state;
-	if (SaveVersion >= 4545)
+	if (SaveVersion >= 4546)
 	{
 		arc << FlatAngle;
 	}

From f41dcc75d1fc8bebe986d2e8fffb0ff2314573ac Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Sun, 1 May 2016 16:33:00 -0500
Subject: [PATCH 04/63] FlatAngle can now be defined directly via properties.

---
 src/thingdef/thingdef_properties.cpp | 9 +++++++++
 wadsrc/static/actors/actor.txt       | 1 +
 2 files changed, 10 insertions(+)

diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp
index 3ec4c624d..7bf72fc48 100644
--- a/src/thingdef/thingdef_properties.cpp
+++ b/src/thingdef/thingdef_properties.cpp
@@ -682,6 +682,15 @@ DEFINE_PROPERTY(scale, F, Actor)
 	defaults->Scale.X = defaults->Scale.Y = id;
 }
 
+//==========================================================================
+//
+//==========================================================================
+DEFINE_PROPERTY(flatangle, F, Actor)
+{
+	PROP_DOUBLE_PARM(id, 0);
+	defaults->FlatAngle = id;
+}
+
 //==========================================================================
 //
 //==========================================================================
diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt
index f47a1d87a..8794debde 100644
--- a/wadsrc/static/actors/actor.txt
+++ b/wadsrc/static/actors/actor.txt
@@ -35,6 +35,7 @@ ACTOR Actor native //: Thinker
 	BloodType "Blood", "BloodSplatter", "AxeBlood"
 	ExplosionDamage 128
 	MissileHeight 32
+	FlatAngle 0
 	
 
 	// Functions

From 0bf7c3e362cc40852b0244dfd2ac8cd89a629b19 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Sun, 1 May 2016 17:19:39 -0500
Subject: [PATCH 05/63] - Removed FlatAngle. This will come back hopefully in
 another commit sometime in the future.

---
 src/actor.h                          |  1 -
 src/p_mobj.cpp                       |  4 ----
 src/thingdef/thingdef_codeptr.cpp    | 21 ---------------------
 src/thingdef/thingdef_data.cpp       |  1 -
 src/thingdef/thingdef_properties.cpp |  9 ---------
 src/version.h                        |  2 +-
 wadsrc/static/actors/actor.txt       |  5 +----
 7 files changed, 2 insertions(+), 41 deletions(-)

diff --git a/src/actor.h b/src/actor.h
index 1d1090c19..7ef63bb94 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -976,7 +976,6 @@ public:
 	DVector3		OldRenderPos;
 
 	DRotator		Angles;
-	DAngle			FlatAngle;
 	DVector3		Vel;
 	double			Speed;
 	double			FloatSpeed;
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index e51a62856..b7d887195 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -263,10 +263,6 @@ void AActor::Serialize(FArchive &arc)
 		<< Vel
 		<< tics
 		<< state;
-	if (SaveVersion >= 4546)
-	{
-		arc << FlatAngle;
-	}
 	if (arc.IsStoring())
 	{
 		int dmg;
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 20848f478..9b8975063 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -6882,24 +6882,3 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection)
 	ACTION_RETURN_BOOL(true);
 }
 
-//===========================================================================
-//
-// A_SetFlatAngle
-//
-// Set actor's flat angle (in degrees). GZDoom only. Requires the 
-// (PITCH)FLATSPRITE flag to have any visible effect.
-//
-//===========================================================================
-DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFlatAngle)
-{
-	PARAM_ACTION_PROLOGUE;
-	PARAM_FLOAT_OPT(flatangle) { flatangle = 0; }
-	PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; }
-	
-	AActor *ref = COPY_AAPTR(self, ptr);
-	if (ref != NULL)
-	{
-		ref->FlatAngle = flatangle;
-	}
-	return 0;
-}
\ No newline at end of file
diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp
index 9669c78ab..8b245e828 100644
--- a/src/thingdef/thingdef_data.cpp
+++ b/src/thingdef/thingdef_data.cpp
@@ -627,7 +627,6 @@ void InitThingdef()
 	PType *array5 = NewArray(TypeSInt32, 5);
 	symt.AddSymbol(new PField(NAME_Alpha,		TypeFloat64,	VARF_Native, myoffsetof(AActor,Alpha)));
 	symt.AddSymbol(new PField(NAME_Angle,		TypeFloat64,	VARF_Native, myoffsetof(AActor,Angles.Yaw)));
-	symt.AddSymbol(new PField(NAME_FlatAngle,	TypeFloat64,	VARF_Native, myoffsetof(AActor,FlatAngle)));
 	symt.AddSymbol(new PField(NAME_Args,		array5,			VARF_Native, myoffsetof(AActor,args)));
 	symt.AddSymbol(new PField(NAME_CeilingZ,	TypeFloat64,	VARF_Native, myoffsetof(AActor,ceilingz)));
 	symt.AddSymbol(new PField(NAME_FloorZ,		TypeFloat64,	VARF_Native, myoffsetof(AActor,floorz)));
diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp
index 7bf72fc48..3ec4c624d 100644
--- a/src/thingdef/thingdef_properties.cpp
+++ b/src/thingdef/thingdef_properties.cpp
@@ -682,15 +682,6 @@ DEFINE_PROPERTY(scale, F, Actor)
 	defaults->Scale.X = defaults->Scale.Y = id;
 }
 
-//==========================================================================
-//
-//==========================================================================
-DEFINE_PROPERTY(flatangle, F, Actor)
-{
-	PROP_DOUBLE_PARM(id, 0);
-	defaults->FlatAngle = id;
-}
-
 //==========================================================================
 //
 //==========================================================================
diff --git a/src/version.h b/src/version.h
index 52b7ea0ba..21d05b3ed 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 4546
+#define SAVEVER 4545
 
 #define SAVEVERSTRINGIFY2(x) #x
 #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt
index 8794debde..6129d9b9b 100644
--- a/wadsrc/static/actors/actor.txt
+++ b/wadsrc/static/actors/actor.txt
@@ -34,9 +34,7 @@ ACTOR Actor native //: Thinker
 	DefThreshold 100
 	BloodType "Blood", "BloodSplatter", "AxeBlood"
 	ExplosionDamage 128
-	MissileHeight 32
-	FlatAngle 0
-	
+	MissileHeight 32	
 
 	// Functions
 	native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
@@ -326,7 +324,6 @@ ACTOR Actor native //: Thinker
 	native state A_CheckSightOrRange(float distance, state label, bool two_dimension = false);
 	native state A_CheckRange(float distance, state label, bool two_dimension = false);
 	action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
-	action native A_SetFlatAngle(float flatangle = 0, int ptr = AAPTR_DEFAULT);
 
 	native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0);
 	native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0);

From def785e4620eb20cf017b19947803260604e59e4 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Mon, 2 May 2016 06:32:33 -0500
Subject: [PATCH 06/63] Removed PITCHFLATSPRITE. FLATSPRITE now encompasses its
 behavior.

---
 src/actor.h                    | 1 -
 src/namedef.h                  | 1 -
 src/thingdef/thingdef_data.cpp | 1 -
 3 files changed, 3 deletions(-)

diff --git a/src/actor.h b/src/actor.h
index 7ef63bb94..e5fb4384e 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -409,7 +409,6 @@ enum ActorRenderFlag
 	RF_WALLSPRITE		= 0x1000,	// Wall sprite
 	RF_FLATSPRITE		= 0x2000,	// Flat sprite
 	RF_VOXELSPRITE		= 0x3000,	// Voxel object
-	RF_PITCHFLATSPRITE	= 0x4000,	// [MC] Flat sprite that rotates around pitch (GZDoom only)
 	RF_INVISIBLE		= 0x8000,	// Don't bother drawing this actor
 
 	RF_FORCEYBILLBOARD		= 0x10000,	// [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting)
diff --git a/src/namedef.h b/src/namedef.h
index 622e5ed5f..17fa9e291 100644
--- a/src/namedef.h
+++ b/src/namedef.h
@@ -300,7 +300,6 @@ xx(ATan2)
 xx(VectorAngle)
 xx(Alpha)
 xx(Angle)
-xx(FlatAngle)
 xx(Args)
 xx(CeilingZ)
 xx(FloorZ)
diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp
index 8b245e828..49b6b0dd8 100644
--- a/src/thingdef/thingdef_data.cpp
+++ b/src/thingdef/thingdef_data.cpp
@@ -269,7 +269,6 @@ static FFlagDef ActorFlagDefs[]=
 			// [fgsfds] Flat sprites
 	DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
 	DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
-	DEFINE_FLAG(RF, PITCHFLATSPRITE, AActor, renderflags),
 
 	// Bounce flags
 	DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),

From 53837de17dd86407fc3fba2a61faf3aa35b78001 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Sun, 5 Jun 2016 15:21:19 -0500
Subject: [PATCH 07/63] Added DONTFLIP flag.

- By default, when viewing a flat sprite from behind, the image is flipped around on the X axis. This may not always be desired, so this flag disables it.
---
 src/actor.h                    | 3 ++-
 src/thingdef/thingdef_data.cpp | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/actor.h b/src/actor.h
index e5fb4384e..333059ce5 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -410,10 +410,11 @@ enum ActorRenderFlag
 	RF_FLATSPRITE		= 0x2000,	// Flat sprite
 	RF_VOXELSPRITE		= 0x3000,	// Voxel object
 	RF_INVISIBLE		= 0x8000,	// Don't bother drawing this actor
+	RF_ROLLSPRITE		= 0x40000,	//[marrub]roll the sprite billboard
+	RF_DONTFLIP			= 0x80000,	// Don't flip it when viewed from behind.
 
 	RF_FORCEYBILLBOARD		= 0x10000,	// [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting)
 	RF_FORCEXYBILLBOARD		= 0x20000,	// [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting)
-	RF_ROLLSPRITE		= 0x40000,	//[marrub]roll the sprite billboard
 };
 
 // This translucency value produces the closest match to Heretic's TINTTAB.
diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp
index 49b6b0dd8..b9e6414ff 100644
--- a/src/thingdef/thingdef_data.cpp
+++ b/src/thingdef/thingdef_data.cpp
@@ -269,6 +269,7 @@ static FFlagDef ActorFlagDefs[]=
 			// [fgsfds] Flat sprites
 	DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
 	DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
+	DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags),
 
 	// Bounce flags
 	DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),

From c6d8125b455625ace7c2a2911de5d822d39847da Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Wed, 22 Jun 2016 13:35:03 +0200
Subject: [PATCH 08/63] - fixed FraggleScript's resurrect function to call
 AActor::Revive to ensure that everything gets reset.

---
 src/fragglescript/t_func.cpp | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp
index f8648808d..ef4f65d34 100644
--- a/src/fragglescript/t_func.cpp
+++ b/src/fragglescript/t_func.cpp
@@ -3473,12 +3473,7 @@ void FParser::SF_Resurrect()
 		mo->SetState(state);
 		mo->Height = mo->GetDefault()->Height;
 		mo->radius = mo->GetDefault()->radius;
-		mo->flags =  mo->GetDefault()->flags;
-		mo->flags2 = mo->GetDefault()->flags2;
-		mo->flags3 = mo->GetDefault()->flags3;
-		mo->flags4 = mo->GetDefault()->flags4;
-		mo->flags5 = mo->GetDefault()->flags5;
-		mo->health = mo->GetDefault()->health;
+		mo->Revive();
 		mo->target = NULL;
 	}
 }

From a3450ab8243b42364b03bfedc46f92ac0d45d6f1 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Wed, 22 Jun 2016 13:37:35 +0200
Subject: [PATCH 09/63] - removed unused cruft in FS code.

---
 src/fragglescript/t_func.cpp | 64 ------------------------------------
 1 file changed, 64 deletions(-)

diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp
index ef4f65d34..aabe797ef 100644
--- a/src/fragglescript/t_func.cpp
+++ b/src/fragglescript/t_func.cpp
@@ -3761,30 +3761,6 @@ void FParser::SF_SetCorona(void)
 	t_return.value.i = 0;
 }
 
-//==========================================================================
-//
-// new for GZDoom: Call a Hexen line special (deprecated, superseded by direct use)
-//
-//==========================================================================
-
-void FParser::SF_Ls()
-{
-	int args[5]={0,0,0,0,0};
-	int spc;
-
-	if (CheckArgs(1))
-	{
-		spc=intvalue(t_argv[0]);
-		for(int i=0;i<5;i++)
-		{
-			if (t_argc>=i+2) args[i]=intvalue(t_argv[i+1]);
-		}
-		if (spc>=0 && spc<256)
-			P_ExecuteSpecial(spc, NULL,Script->trigger,false, args[0],args[1],args[2],args[3],args[4]);
-	}
-}
-
-
 //==========================================================================
 //
 // new for GZDoom: Gets the levelnum
@@ -4019,17 +3995,6 @@ void  FParser::SF_KillInSector()
 	}
 }
 
-//==========================================================================
-//
-// new for GZDoom: Sets a sector's type
-//
-//==========================================================================
-
-void FParser::SF_SectorType(void)
-{
-	// I don't think this was ever used publicly so I'm not going to bother fixing it.
-}
-
 //==========================================================================
 //
 // new for GZDoom: Sets a new line trigger type (Doom format!)
@@ -4064,30 +4029,6 @@ void FParser::SF_SetLineTrigger()
 }
 
 
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-void FParser::SF_ChangeTag()
-{
-	// Development garbage!
-}
-
-
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-void FParser::SF_WallGlow()
-{
-	// Development garbage!
-}
-
-
 //==========================================================================
 //
 // new for GZDoom: Call a Hexen line special
@@ -4505,13 +4446,10 @@ void init_functions(void)
 	// new for GZDoom
 	gscr->NewFunction("spawnshot2", &FParser::SF_SpawnShot2);
 	gscr->NewFunction("setcolor", &FParser::SF_SetColor);
-	gscr->NewFunction("sectortype", &FParser::SF_SectorType);
-	gscr->NewFunction("wallglow", &FParser::SF_WallGlow);
 	gscr->NewFunction("objradius", &FParser::SF_MobjRadius);
 	gscr->NewFunction("objheight", &FParser::SF_MobjHeight);
 	gscr->NewFunction("thingcount", &FParser::SF_ThingCount);
 	gscr->NewFunction("killinsector", &FParser::SF_KillInSector);
-	gscr->NewFunction("changetag", &FParser::SF_ChangeTag);
 	gscr->NewFunction("levelnum", &FParser::SF_LevelNum);
 
 	// new inventory
@@ -4520,8 +4458,6 @@ void init_functions(void)
 	gscr->NewFunction("checkinventory", &FParser::SF_CheckInventory);
 	gscr->NewFunction("setweapon", &FParser::SF_SetWeapon);
 
-	gscr->NewFunction("ls", &FParser::SF_Ls);	// execute Hexen type line special
-
 	// Dummies - shut up warnings
 	gscr->NewFunction("setcorona", &FParser::SF_SetCorona);
 }

From f8ae166281a07b7b0f235e7186f3c580b7d3f420 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Mon, 27 Jun 2016 12:01:11 +0200
Subject: [PATCH 10/63] - fixed return value inversion of FS's ceilingheight
 and floorheight functions.

---
 src/fragglescript/t_func.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp
index aabe797ef..f02843c89 100644
--- a/src/fragglescript/t_func.cpp
+++ b/src/fragglescript/t_func.cpp
@@ -1573,7 +1573,7 @@ void FParser::SF_FloorHeight(void)
 					sectors[i].floorplane.PointToDist (sectors[i].centerspot, dest),
 					crush? 10:-1, 
 					(dest > sectors[i].CenterFloor()) ? 1 : -1,
-					false) != EMoveResult::crushed)
+					false) == EMoveResult::crushed)
 				{
 					returnval = 0;
 				}
@@ -1662,7 +1662,7 @@ void FParser::SF_CeilingHeight(void)
 					sectors[i].ceilingplane.PointToDist (sectors[i].centerspot, dest), 
 					crush? 10:-1,
 					(dest > sectors[i].CenterCeiling()) ? 1 : -1,
-					false) != EMoveResult::crushed)
+					false) == EMoveResult::crushed)
 				{
 					returnval = 0;
 				}

From 6cf96372ba363ef9f9674f97cb43736f53984e60 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Wed, 29 Jun 2016 12:13:24 +0200
Subject: [PATCH 11/63] - fixed: incorrect flag masking for polyobjects
 disabled all line portals.

---
 src/portal.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/portal.cpp b/src/portal.cpp
index f180a4fbf..bf919f09a 100644
--- a/src/portal.cpp
+++ b/src/portal.cpp
@@ -288,7 +288,7 @@ static void SetRotation(FLinePortal *port)
 			}
 			else
 			{
-				port->mFlags &= PORTF_POLYOBJ;
+				port->mFlags &= ~PORTF_POLYOBJ;
 			}
 		}
 		else

From 41d20fa6cf585b83ac64c2269a0b5c55cc10a656 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Thu, 23 Jun 2016 10:28:05 -0500
Subject: [PATCH 12/63] Fixed freeze with A_ClearOverlays.

---
 src/p_pspr.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp
index ebfc14da3..e63490110 100644
--- a/src/p_pspr.cpp
+++ b/src/p_pspr.cpp
@@ -1169,8 +1169,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ClearOverlays)
 
 	int count = 0;
 	DPSprite *pspr = player->psprites;
+	int startID = (pspr != nullptr) ? pspr->GetID() : start;
+	bool first = true;
 	while (pspr != nullptr)
 	{
+		if (pspr->GetID() == startID)
+		{
+			if (first)
+				first = false;
+			else
+				break;
+		}
 		int id = pspr->GetID();
 
 		//Do not wipe out layer 0. Ever.

From 43e62c4236ed22227a870aa1865a1e8a98113c3e Mon Sep 17 00:00:00 2001
From: jayman2000 <swagfortress@gmail.com>
Date: Fri, 24 Jun 2016 17:54:43 -0400
Subject: [PATCH 13/63] Added sliders in the display options menu to control
 movebob and stillbob.

---
 wadsrc/static/language.eng | 2 ++
 wadsrc/static/menudef.txt  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/wadsrc/static/language.eng b/wadsrc/static/language.eng
index ca27bf80a..2f61f7496 100644
--- a/wadsrc/static/language.eng
+++ b/wadsrc/static/language.eng
@@ -108,3 +108,5 @@ CMPTMNU_SECTORSOUNDS = "Sector sounds use centre as source";
 OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colours only";
 C_GRAY = "\ccgrey";
 C_DARKGRAY = "\cudark grey";
+DSPLYMNU_MOVEBOB = "View bob ammount while moving";
+DSPLYMNU_STILLBOB = "View bob ammount while not moving";
diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt
index ff395ff2a..bb854f378 100644
--- a/wadsrc/static/menudef.txt
+++ b/wadsrc/static/menudef.txt
@@ -688,6 +688,8 @@ OptionMenu "VideoOptions"
 	Option "$DSPLYMNU_NOMONSTERINTERPOLATION",	"nomonsterinterpolation", "NoYes"
 	Slider "$DSPLYMNU_MENUDIM",					"dimamount", 0, 1.0, 0.05, 2
 	ColorPicker "$DSPLYMNU_DIMCOLOR",			"dimcolor"
+	Slider "$DSPLYMNU_MOVEBOB",			"movebob", 0, 1.0, 0.05, 2
+	Slider "$DSPLYMNU_STILLBOB",		"stillbob", 0, 1.0, 0.05, 2
 }
 
 //-------------------------------------------------------------------------------------------

From 593e2f7641adffd852c34e03e0aea91f1aefa621 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Wed, 29 Jun 2016 13:03:39 +0200
Subject: [PATCH 14/63] - fixed spelling.

---
 wadsrc/static/language.eng | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/wadsrc/static/language.eng b/wadsrc/static/language.eng
index 2f61f7496..ed0f95a9a 100644
--- a/wadsrc/static/language.eng
+++ b/wadsrc/static/language.eng
@@ -108,5 +108,5 @@ CMPTMNU_SECTORSOUNDS = "Sector sounds use centre as source";
 OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colours only";
 C_GRAY = "\ccgrey";
 C_DARKGRAY = "\cudark grey";
-DSPLYMNU_MOVEBOB = "View bob ammount while moving";
-DSPLYMNU_STILLBOB = "View bob ammount while not moving";
+DSPLYMNU_MOVEBOB = "View bob amount while moving";
+DSPLYMNU_STILLBOB = "View bob amount while not moving";

From 4defb6e9673f5bc75939c336f04b540feaffbca5 Mon Sep 17 00:00:00 2001
From: Edoardo Prezioso <edo88@email.it>
Date: Tue, 21 Jun 2016 12:44:03 +0200
Subject: [PATCH 15/63] - Fix myoffsetof using misaligned pointer access.

That could be a problem for particularly pedantic platforms.
---
 src/cmdlib.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cmdlib.h b/src/cmdlib.h
index 05e515374..b035842cd 100644
--- a/src/cmdlib.h
+++ b/src/cmdlib.h
@@ -16,7 +16,7 @@
 #include <stdarg.h>
 
 // the dec offsetof macro doesnt work very well...
-#define myoffsetof(type,identifier) ((size_t)&((type *)1)->identifier - 1)
+#define myoffsetof(type,identifier) ((size_t)&((type *)alignof(type))->identifier - alignof(type))
 
 int		Q_filelength (FILE *f);
 bool FileExists (const char *filename);

From c6fb35ed52621d026ab88f21ac97831d3863c9d8 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Thu, 30 Jun 2016 10:27:14 +0200
Subject: [PATCH 16/63] - added per-item colors for static text items in the
 menu.

For option menus this replaces the 'highlighted' parameter with an actual color, for list menus it adds a new parameter.
---
 src/menu/menudef.cpp       | 39 +++++++++++++++++++++++++-------------
 src/menu/optionmenuitems.h | 12 +++++++++---
 2 files changed, 35 insertions(+), 16 deletions(-)

diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp
index d1753c405..6d5e3dd64 100644
--- a/src/menu/menudef.cpp
+++ b/src/menu/menudef.cpp
@@ -306,7 +306,15 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc)
 			int y = sc.Number;
 			sc.MustGetStringName(",");
 			sc.MustGetString();
-			FListMenuItem *it = new FListMenuItemStaticText(x, y, sc.String, desc->mFont, desc->mFontColor, centered);
+			FString label = sc.String;
+			EColorRange cr = desc->mFontColor;
+			if (sc.CheckString(","))
+			{
+				sc.MustGetString();
+				cr = V_FindFontColor(sc.String);
+				if (cr == CR_UNTRANSLATED && !sc.Compare("untranslated")) cr = desc->mFontColor;
+			}
+			FListMenuItem *it = new FListMenuItemStaticText(x, y, label, desc->mFont, cr, centered);
 			desc->mItems.Push(it);
 		}
 		else if (sc.Compare("PatchItem"))
@@ -648,6 +656,21 @@ static void ParseOptionSettings(FScanner &sc)
 //
 //=============================================================================
 
+static EColorRange ParseOptionColor(FScanner &sc, FOptionMenuDescriptor *desc)
+{
+	EColorRange cr = OptionSettings.mFontColor;
+	if (sc.CheckString(","))
+	{
+		sc.MustGetString();
+		EColorRange cr = V_FindFontColor(sc.String);
+		if (cr == CR_UNTRANSLATED && !sc.Compare("untranslated") && isdigit(sc.String[0]))
+		{
+			if (strtol(sc.String, NULL, 0)) cr = OptionSettings.mFontColorHeader;
+		}
+	}
+	return cr;
+}
+
 static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc)
 {
 	sc.MustGetStringName("{");
@@ -784,12 +807,7 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc)
 		{
 			sc.MustGetString();
 			FString label = sc.String;
-			bool cr = false;
-			if (sc.CheckString(","))
-			{
-				sc.MustGetNumber();
-				cr = !!sc.Number;
-			}
+			EColorRange cr = ParseOptionColor(sc, desc);
 			FOptionMenuItem *it = new FOptionMenuItemStaticText(label, cr);
 			desc->mItems.Push(it);
 		}
@@ -803,12 +821,7 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc)
 			sc.MustGetStringName(",");
 			sc.MustGetString();
 			FName action = sc.String;
-			bool cr = false;
-			if (sc.CheckString(","))
-			{
-				sc.MustGetNumber();
-				cr = !!sc.Number;
-			}
+			EColorRange cr = ParseOptionColor(sc, desc);
 			FOptionMenuItem *it = new FOptionMenuItemStaticTextSwitchable(label, label2, action, cr);
 			desc->mItems.Push(it);
 		}
diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h
index 8a1840027..3131e35f7 100644
--- a/src/menu/optionmenuitems.h
+++ b/src/menu/optionmenuitems.h
@@ -483,7 +483,13 @@ public:
 	FOptionMenuItemStaticText(const char *label, bool header)
 		: FOptionMenuItem(label, NAME_None, true)
 	{
-		mColor = header? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
+		mColor = header ? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
+	}
+
+	FOptionMenuItemStaticText(const char *label, EColorRange cr)
+		: FOptionMenuItem(label, NAME_None, true)
+	{
+		mColor = cr;
 	}
 
 	int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
@@ -512,10 +518,10 @@ class FOptionMenuItemStaticTextSwitchable : public FOptionMenuItem
 	int mCurrent;
 
 public:
-	FOptionMenuItemStaticTextSwitchable(const char *label, const char *label2, FName action, bool header)
+	FOptionMenuItemStaticTextSwitchable(const char *label, const char *label2, FName action, EColorRange cr)
 		: FOptionMenuItem(label, action, true)
 	{
-		mColor = header? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
+		mColor = cr;
 		mAltText = label2;
 		mCurrent = 0;
 	}

From fc3682006a8700fc7097a43eb023de6847923be1 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Thu, 30 Jun 2016 11:30:32 +0200
Subject: [PATCH 17/63] - fixed PointOnSide functions to consider 'on the line'
 as 'in front of'.

The bad code was taken from the 2005 floating point rewrite that, by comparing the value with '> -EQUAL_EPSILON', returned 1 for any value close to 0 (as 'on the line') so it was mistakenly reported as 'behind the line'.
---
 src/p_maputl.h | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/p_maputl.h b/src/p_maputl.h
index e5a8a5f4f..0e87e501a 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -38,17 +38,22 @@ struct intercept_t
 
 inline int P_PointOnLineSidePrecise(double x, double y, const line_t *line)
 {
-	return (y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - x) * line->Delta().Y > -EQUAL_EPSILON;
+	return (y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - x) * line->Delta().Y > EQUAL_EPSILON;
 }
 
 inline int P_PointOnLineSidePrecise(const DVector2 &pt, const line_t *line)
 {
-	return (pt.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pt.X) * line->Delta().Y > -EQUAL_EPSILON;
+	return (pt.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pt.X) * line->Delta().Y > EQUAL_EPSILON;
 }
 
+extern line_t *lines;
 inline int P_PointOnLineSide (double x, double y, const line_t *line)
 {
 	extern int P_VanillaPointOnLineSide(double x, double y, const line_t* line);
+	if (line - lines == 6180)
+	{
+		int a = 0;
+	}
 
 	return i_compatflags2 & COMPATF2_POINTONLINE
 		? P_VanillaPointOnLineSide(x, y, line) : P_PointOnLineSidePrecise(x, y, line);
@@ -73,12 +78,12 @@ inline int P_PointOnLineSide(const DVector2 & p, const line_t *line)
 
 inline int P_PointOnDivlineSide(double x, double y, const divline_t *line)
 {
-	return (y - line->y) * line->dx + (line->x - x) * line->dy > -EQUAL_EPSILON;
+	return (y - line->y) * line->dx + (line->x - x) * line->dy > EQUAL_EPSILON;
 }
 
 inline int P_PointOnDivlineSide(const DVector2 &pos, const divline_t *line)
 {
-	return (pos.Y - line->y) * line->dx + (line->x - pos.X) * line->dy > -EQUAL_EPSILON;
+	return (pos.Y - line->y) * line->dx + (line->x - pos.X) * line->dy > EQUAL_EPSILON;
 }
 
 //==========================================================================

From 7bdb98cc0b3735c4c95cd45c11183e1147bfff26 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Thu, 30 Jun 2016 11:31:00 +0200
Subject: [PATCH 18/63] - removed debug stuff.

---
 src/p_maputl.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/p_maputl.h b/src/p_maputl.h
index 0e87e501a..81d3c9d13 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -46,15 +46,9 @@ inline int P_PointOnLineSidePrecise(const DVector2 &pt, const line_t *line)
 	return (pt.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pt.X) * line->Delta().Y > EQUAL_EPSILON;
 }
 
-extern line_t *lines;
 inline int P_PointOnLineSide (double x, double y, const line_t *line)
 {
 	extern int P_VanillaPointOnLineSide(double x, double y, const line_t* line);
-	if (line - lines == 6180)
-	{
-		int a = 0;
-	}
-
 	return i_compatflags2 & COMPATF2_POINTONLINE
 		? P_VanillaPointOnLineSide(x, y, line) : P_PointOnLineSidePrecise(x, y, line);
 }

From 148de414e0b43d909b9690f726bd82253b564e07 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Sun, 3 Jul 2016 13:32:40 +0200
Subject: [PATCH 19/63] - fixed: Checking for quest item 0 should not print an
 error message but silently fail.

---
 strifehelp.acs                                |   8 +++++++-
 .../static/filter/game-strife/acs/strfhelp.o  | Bin 3184 -> 3288 bytes
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/strifehelp.acs b/strifehelp.acs
index 9176ca006..495893edf 100644
--- a/strifehelp.acs
+++ b/strifehelp.acs
@@ -1,6 +1,7 @@
+#library "strfhelp"
+
 #include "zcommon.acs"
 
-#library "strfhelp"
 
 #define VDOORSPEED  16
 #define VDOORWAIT   150
@@ -69,6 +70,7 @@ script << 0 >> (int type, int tag)
 	
 	case 230:
 		i = GetLineRowOffset() & 31;
+		if (i == 0) break;
 		if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
 		{
 			Door_Open (tag, VDOORSPEED);
@@ -78,6 +80,7 @@ script << 0 >> (int type, int tag)
 		
 	case 227:
 		i = GetLineRowOffset() & 31;
+		if (i == 0) break;
 		if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
 		{
 			Door_Close (tag, VDOORSPEED);
@@ -126,6 +129,7 @@ script << 0 >> (int type, int tag)
 
 	case 193:
 		i = GetLineRowOffset() & 31;
+		if (i == 0) break;
 		if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
 		{
 			Floor_LowerToLowest (tag, 8);
@@ -158,6 +162,7 @@ script << 0 >> (int type, int tag)
 
 	case 187:
 		i = GetLineRowOffset() & 31;
+		if (i == 0) break;
 		if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
 		{
 			ClearForceField (tag);
@@ -203,6 +208,7 @@ script << 0 >> (int type, int tag)
 	
 	case 216:
 		i = GetLineRowOffset() & 31;
+		if (i == 0) break;
 		if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
 		{
 			Door_Raise (tag, VDOORSPEED, VDOORWAIT);
diff --git a/wadsrc/static/filter/game-strife/acs/strfhelp.o b/wadsrc/static/filter/game-strife/acs/strfhelp.o
index 45664cbc4e92ae82c81c0c8382020e381bd0e069..521d8871455b1583c77450c88d8e22cfebb852a6 100644
GIT binary patch
delta 1594
zcmZuyOGs2v82<0PG<EFiWHZ%7nHXYJ1eeO}VX0H;;s~Mz(I(W0qG-{^&2`(Rh*3d{
zAX*%v8plTzJr-qFP^rCzinwX-&85epUEhD^-kg~l_~$$4`@jEn?wLDwWNLxAwYHfi
z3y7j*l>3S7V!33;0#DQ<DJ05?$mj{c>6xJT9_a~f7uDdRn$-RI&B~P#(E6W%LvBD`
zDnLf8xaa{Xqga?Hc(u-w=6<7_m+N`yq>e~!zPOl*&-It2v!jYl>OS4?=B+}yscdoj
zI6vUb9><)csd@gU$84Cq6s#oQ52Hf4lSF|A6)M{*w3MXIl{98aGESre&g`0<D!{jl
z=UIh1y5*d0w{py$t=xc-E~Jz3BU;3KmSWn921%owMCw?$sR+JG!!cni!Gwmk`&99a
zmhwISwp0o(swMT_K!FNqk~B{ku8^O+Xh=!AYRo{m+1RaivaJXu+lr;;9uL_eFOg1#
zlJ3nH$Dl$J{>v(<thVBf;&>*<Pwh-5wGq@n1{KwY^fFw|@Fg+oIq0-6p=%VMAZ(GF
ztX-{gGp<gDB)iD?338D1UOp5%TmXh|u`EUaW|<cgi_v6@+>#kp2{J1xZh1<o)Gq)X
z;QH9%e9^9AYdAJ&N$sR@0E8;*2y^pTxI*;DS9_!8*>o@WEN+3}iIC6^KSFblRmQr^
zZro&DtorVZfUw*YA?El{b(<ygPRd$tqea#ufe~by&%lYVUwVKOjL$OJgv|9WL{O5n
zS(zP?{t~hGZ?5=n@0wsQwnH(TLQcZy0kg<VwX&1n7fyaI&A}n@4r;XPQ{@X?x7WSv
zUc7Ah5PG>genN#HhLOAj`=Be2Su$qX3)L{{%hqWnMES5n%_OS8g4;BJD{<{l0r}qc
z1B<~Y9RC2Lx)nra;771ujbp#!;8oyh@YjGN&|L>E2i^cSA@5C~3A_d5dbfdZQJ?O>
z>XGO!kc*DNaOLS9tP=_D0}sRh0N95F4}nv_M-Gky&p|f{JOO+HJP-YIAjiC51pg9f
zpzteT0`dH&+xH8L*H}D7z#9kO1E;Z{2G+o4U`JseU}H$|5jYq28TK2AzW{lnufQ4L
cH(&!0?-mOAhbseX1Ns^Kdhkcl4px2s0G+ya8UO$Q

delta 1509
zcmZ`(TSyd97(TN%MO_<Rbyi#K;)_%g!q~-14P(0qonp~M>20%o2*QVos7C6cr-)pz
z3qA#LD01@_-K<DVgG4L32nI1_k@e6}JylTOe`Z!)vxR@YIp6vI@BIHcXJ<U$3K|=$
zBWzy=V<DywdKj~^#iA|wu8?bt#Ttbxu$ix5m{f%7O^@g$zWEf}6N)rjA%bR%9|9>t
zcsW2Xt4(3-)eq9^8hUlCg2GVp_-Q*o)tfs_gS{--F4d!Y6TWL<cW18npMu}aQJ{Dh
z;6K0$=J~GwvV9rzZ9_i>*l4k0Yc$2t6yhbMbUB*&dajTP&r+vj)pT~NUh*@$CCX9r
z{y8L8i#lZ+GaG%*Rz<VAnZi=ywlftL#AAsT=6zByMs;2I&r!URk}kE~mmw891k2%5
zAmxY-l>f0MtyMlPqWcY(Jl$xPU6Ud=g?7OTxEWJfreH&Pd>K?&)!Qj;#5yxp!z+?G
zI-8xz)Ot|SBr2rzs72UL?HWIf3AoYzLs!E)Fs>CF%w2V&0ym@y6=dmGKz1{=op!;}
zGQiLc6xm2XFF9fUTxL}!XT6;_3m&O%hAA{+X<r?$GAao-!qU=t0XnV~Rb=Kjg>ptO
z1R?97RUu4GBjIw+V@KSfhREz$YJ#_bAwL*e+6Y!SAssg*mzOYWCDk{l4sy2%e%~Fl
z+_{wlv+XgxxS8~$Gx}u03JPy7|2>@)Yw(o%%kYox38TG~xLyKgp<%DFmHy$56E#T5
z0e&26EaZ_3WhSQGiK~6do>tqb4myiY5WO&O!q}gXhfNVStpa&a@?l{&=o^xbFmc?h
z7(sRFK-_e87C=|@B5)Xd97yxmf!XpX85_sA593LUZ#Z}pSdJ2I0h__omtg`vcY#H~
zeqc559+3PV0*wcF3?P0YVGwu}@d(j|7(%QBKMX8F!eiiW7(4-X07o1g1=d0L6j%*>
z2CRqv1@J23CE^(P*T5F!jRS83Cm3sFry!&+6yZDIdEk3sDPj^4L3}_&(b-4f0>mdo
l9EMXs>f|%<B<8;Wr!b~n?D6!r`BwQ<9ak0K^gUqZ?=OlySHJ)O


From 1b6a850bf68682e15383f253a4963784c62a6626 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Sun, 3 Jul 2016 13:39:33 +0200
Subject: [PATCH 20/63] - fixed: DAnimatedDoor's main constructor did not
 disable ceiling interpolation.

---
 src/p_doors.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/p_doors.cpp b/src/p_doors.cpp
index d6a5f3a44..b16bd4435 100644
--- a/src/p_doors.cpp
+++ b/src/p_doors.cpp
@@ -688,7 +688,7 @@ void DAnimatedDoor::Tick ()
 //============================================================================
 
 DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim)
-	: DMovingCeiling (sec)
+	: DMovingCeiling (sec, false)
 {
 	double topdist;
 	FTextureID picnum;

From d6d9057f1f745a3aaed2c52bc3b89a8b49aba070 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Sun, 3 Jul 2016 13:42:54 +0200
Subject: [PATCH 21/63] - removed the old way to stop the AnimatedDoor
 interpolation, now that the parent class can be told that we do not want one.
 This old code was no longer functionsl.

---
 src/p_doors.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/p_doors.cpp b/src/p_doors.cpp
index b16bd4435..ab551de1b 100644
--- a/src/p_doors.cpp
+++ b/src/p_doors.cpp
@@ -693,9 +693,6 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay,
 	double topdist;
 	FTextureID picnum;
 
-	// The DMovingCeiling constructor automatically sets up an interpolation for us.
-	// Stop it, since the ceiling is moving instantly here.
-	StopInterpolation();
 	m_DoorAnim = anim;
 
 	m_Line1 = line;

From d87665bfe0961f05414bc19da3ffeb1207f0e0e9 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Mon, 4 Jul 2016 00:39:35 +0200
Subject: [PATCH 22/63] - fixed: A_CheckTerrain must add to the actor's current
 velocity, not set it.

---
 src/g_strife/a_strifestuff.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp
index 8b5788d44..4e49121fa 100644
--- a/src/g_strife/a_strifestuff.cpp
+++ b/src/g_strife/a_strifestuff.cpp
@@ -317,7 +317,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
 			int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
 			double speed = (anglespeed % 10) / 16.;
 			DAngle an = (anglespeed / 10) * (360 / 8.);
-			self->VelFromAngle(an, speed);
+			self->Thrust(an, speed);
 		}
 	}
 	return 0;

From b81876698fa67bcd426f2403ea4509a41e0363ce Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Mon, 4 Jul 2016 22:36:27 +0200
Subject: [PATCH 23/63] - changed P_ChangeSector so that for bridges it only
 keeps the floorz and ceilingz of the spawn position.

This is necessary to prevent moving sectors from altering the bridge's z-position. The bridge should remain at its current z, even if the sector change would cause floorz or ceilingz to be changed in a way that would make P_ZMovement adjust the bridge.
---
 src/p_map.cpp | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/p_map.cpp b/src/p_map.cpp
index cf7655917..2fe41b17b 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -5466,14 +5466,25 @@ bool P_AdjustFloorCeil(AActor *thing, FChangePosition *cpos)
 	}
 
 	bool isgood = P_CheckPosition(thing, thing->Pos(), tm);
-	thing->floorz = tm.floorz;
-	thing->ceilingz = tm.ceilingz;
-	thing->dropoffz = tm.dropoffz;		// killough 11/98: remember dropoffs
-	thing->floorpic = tm.floorpic;
-	thing->floorterrain = tm.floorterrain;
-	thing->floorsector = tm.floorsector;
-	thing->ceilingpic = tm.ceilingpic;
-	thing->ceilingsector = tm.ceilingsector;
+	if (!(thing->flags4 & MF4_ACTLIKEBRIDGE))
+	{
+		thing->floorz = tm.floorz;
+		thing->ceilingz = tm.ceilingz;
+		thing->dropoffz = tm.dropoffz;		// killough 11/98: remember dropoffs
+		thing->floorpic = tm.floorpic;
+		thing->floorterrain = tm.floorterrain;
+		thing->floorsector = tm.floorsector;
+		thing->ceilingpic = tm.ceilingpic;
+		thing->ceilingsector = tm.ceilingsector;
+	}
+	else
+	{
+		// Bridges only keep the info at their spawn position
+		// This is necessary to prevent moving sectors from altering the bridge's z-position.
+		// The bridge should remain at its current z, even if the sector change would cause
+		// floorz or ceilingz to be changed in a way that would make P_ZMovement adjust the bridge.
+		P_FindFloorCeiling(thing, FFCF_ONLYSPAWNPOS);
+	}
 
 	// restore the PASSMOBJ flag but leave the other flags alone.
 	thing->flags2 = (thing->flags2 & ~MF2_PASSMOBJ) | flags2;

From b2a88c1abdb28e131af9ec68077553fef297ac47 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Tue, 5 Jul 2016 01:17:12 +0200
Subject: [PATCH 24/63] - fixed: mapthinghexen_t::flags needs to be unsigned.

This is necessary so that an incorrectly set 0x8000 bit won't enable all high flags.
---
 src/doomdata.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/doomdata.h b/src/doomdata.h
index 4e4976800..f809f05ea 100644
--- a/src/doomdata.h
+++ b/src/doomdata.h
@@ -334,7 +334,7 @@ struct mapthinghexen_t
 	SWORD		z;
 	SWORD		angle;
 	SWORD		type;
-	SWORD		flags;
+	WORD		flags;
 	BYTE		special;
 	BYTE		args[5];
 };

From e401588f40e43ae6bca9c6f823c30edb3b5ad1e7 Mon Sep 17 00:00:00 2001
From: Braden Obrzut <admin@maniacsvault.net>
Date: Mon, 11 Jul 2016 01:17:45 -0400
Subject: [PATCH 25/63] - Set -stdlib=libc++ and disable
 inconsistent-missing-override warning with OS X Clang (the latter may be
 useful for recent versions of Clang in general, but I can't tell at the
 moment.)

---
 src/CMakeLists.txt | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 93a165fb1..67b7dbb17 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -484,6 +484,9 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
 		set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" )
 		set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" )
 	endif()
+	if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+		set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" )
+	endif()
 	set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" )
 	set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" )
 
@@ -511,6 +514,12 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
 		endif ()
 	endif ()
 
+	# With standard Apple tools -stdlib=libc++ needs to be specified in order to get
+	# C++11 support using SDKs 10.7 and 10.8.
+	if ( APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
+		set( CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}" )
+	endif ()
+
 	# Remove extra warnings when using the official DirectX headers.
 	# Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid,
 	# which is a royal pain. The previous version I had been using was fine with them.

From 1f2c8181bb7e869d16f912cfbcb3cd6702c65238 Mon Sep 17 00:00:00 2001
From: Blue-Shadow <blueshadow_941@yahoo.com>
Date: Tue, 5 Jul 2016 16:15:39 +0300
Subject: [PATCH 26/63] Added IfWaterLevel SBARINFO command

---
 src/g_shared/sbarinfo_commands.cpp | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp
index a09c49303..b4a011510 100644
--- a/src/g_shared/sbarinfo_commands.cpp
+++ b/src/g_shared/sbarinfo_commands.cpp
@@ -3440,6 +3440,30 @@ class CommandIfInvulnerable : public SBarInfoNegatableFlowControl
 
 ////////////////////////////////////////////////////////////////////////////////
 
+class CommandIfWaterLevel : public SBarInfoNegatableFlowControl
+{
+	public:
+		CommandIfWaterLevel(SBarInfo *script) : SBarInfoNegatableFlowControl(script)
+		{
+		}
+
+		void	ParseNegatable(FScanner &sc, bool fullScreenOffsets)
+		{
+			sc.MustGetToken(TK_IntConst);
+			value = sc.Number;
+		}
+		void	Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged)
+		{
+			SBarInfoNegatableFlowControl::Tick(block, statusBar, hudChanged);
+
+			SetTruth(statusBar->CPlayer->mo->waterlevel >= value, block, statusBar);
+		}
+	protected:
+		int value;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
 static const char *SBarInfoCommandNames[] =
 {
 	"drawimage", "drawnumber", "drawswitchableimage",
@@ -3450,7 +3474,7 @@ static const char *SBarInfoCommandNames[] =
 	"isselected", "usesammo", "usessecondaryammo",
 	"hasweaponpiece", "inventorybarnotvisible",
 	"weaponammo", "ininventory", "alpha", "ifhealth",
-	"ifinvulnerable",
+	"ifinvulnerable", "ifwaterlevel",
 	NULL
 };
 
@@ -3464,7 +3488,7 @@ enum SBarInfoCommands
 	SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO,
 	SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE,
 	SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA, SBARINFO_IFHEALTH,
-	SBARINFO_IFINVULNERABLE,
+	SBARINFO_IFINVULNERABLE, SBARINFO_IFWATERLEVEL,
 };
 
 SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
@@ -3499,6 +3523,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
 			case SBARINFO_ALPHA: return new CommandAlpha(script);
 			case SBARINFO_IFHEALTH: return new CommandIfHealth(script);
 			case SBARINFO_IFINVULNERABLE: return new CommandIfInvulnerable(script);
+			case SBARINFO_IFWATERLEVEL: return new CommandIfWaterLevel(script);
 		}
 
 		sc.ScriptError("Unknown command '%s'.\n", sc.String);

From 7d1dc46665e76697c6abc02acd9da8628f5809d5 Mon Sep 17 00:00:00 2001
From: subenji <subenji99@gmail.com>
Date: Thu, 7 Jul 2016 15:46:54 +0100
Subject: [PATCH 27/63] Implemented fix discussed in
 http://forum.zdoom.org/viewtopic.php?f=2&t=52428 rearding UserVar corruption
 in savegames

---
 src/farchive.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/farchive.cpp b/src/farchive.cpp
index fc3d75bbb..6697fd5b7 100644
--- a/src/farchive.cpp
+++ b/src/farchive.cpp
@@ -728,13 +728,13 @@ void FArchive::WriteByte(BYTE val)
 
 void FArchive::WriteInt16(WORD val)
 {
-	WORD out = LittleShort(val);
+	WORD out = SWAP_WORD(val);
 	m_File->Write(&out, 2);
 }
 
 void FArchive::WriteInt32(DWORD val)
 {
-	int out = LittleLong(val);
+	int out = SWAP_DWORD(val);
 	m_File->Write(&out, 4);
 }
 

From 371896b2ccc4cd1b71943e6dec59deda35ae6185 Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Mon, 4 Jul 2016 02:19:52 +0200
Subject: [PATCH 28/63] Properly use the boolean type in expressions

This fixes things like 'if (GetCVar(x))' not working
---
 src/thingdef/thingdef_exp.cpp        |   4 +-
 src/thingdef/thingdef_exp.h          |  33 +--
 src/thingdef/thingdef_expression.cpp | 338 +++++++++++++--------------
 3 files changed, 189 insertions(+), 186 deletions(-)

diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp
index ca812e2e5..35932e0be 100644
--- a/src/thingdef/thingdef_exp.cpp
+++ b/src/thingdef/thingdef_exp.cpp
@@ -331,11 +331,11 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
 	}
 	else if (sc.CheckToken(TK_True))
 	{
-		return new FxConstant(1, scpos);
+		return new FxConstant(true, scpos);
 	}
 	else if (sc.CheckToken(TK_False))
 	{
-		return new FxConstant(0, scpos);
+		return new FxConstant(false, scpos);
 	}
 	else if (sc.CheckToken(TK_IntConst))
 	{
diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h
index ac6b7eda3..58820ea15 100644
--- a/src/thingdef/thingdef_exp.h
+++ b/src/thingdef/thingdef_exp.h
@@ -203,7 +203,6 @@ protected:
 public:
 	virtual ~FxExpression() {}
 	virtual FxExpression *Resolve(FCompileContext &ctx);
-	FxExpression *ResolveAsBoolean(FCompileContext &ctx);
 	
 	virtual bool isConstant() const;
 	virtual void RequestAddress();
@@ -280,6 +279,13 @@ class FxConstant : public FxExpression
 	ExpVal value;
 
 public:
+	FxConstant(bool val, const FScriptPosition &pos) : FxExpression(pos)
+	{
+		ValueType = value.Type = TypeBool;
+		value.Int = val;
+		isresolved = true;
+	}
+
 	FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos)
 	{
 		ValueType = value.Type = TypeSInt32;
@@ -358,6 +364,19 @@ public:
 //
 //==========================================================================
 
+class FxBoolCast : public FxExpression
+{
+	FxExpression *basex;
+
+public:
+
+	FxBoolCast(FxExpression *x);
+	~FxBoolCast();
+	FxExpression *Resolve(FCompileContext&);
+
+	ExpEmit Emit(VMFunctionBuilder *build);
+};
+
 class FxIntCast : public FxExpression
 {
 	FxExpression *basex;
@@ -384,18 +403,6 @@ public:
 	ExpEmit Emit(VMFunctionBuilder *build);
 };
 
-class FxCastStateToBool : public FxExpression
-{
-	FxExpression *basex;
-
-public:
-	FxCastStateToBool(FxExpression *x);
-	~FxCastStateToBool();
-	FxExpression *Resolve(FCompileContext&);
-
-	ExpEmit Emit(VMFunctionBuilder *build);
-};
-
 //==========================================================================
 //
 //	FxSign
diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp
index 04410189a..463156d7f 100644
--- a/src/thingdef/thingdef_expression.cpp
+++ b/src/thingdef/thingdef_expression.cpp
@@ -177,38 +177,6 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx)
 	return this;
 }
 
-
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-FxExpression *FxExpression::ResolveAsBoolean(FCompileContext &ctx)
-{
-	///FIXME: Use an actual boolean type
-	FxExpression *x = Resolve(ctx);
-	if (x != NULL)
-	{
-		if (x->ValueType->GetRegType() == REGT_INT)
-		{
-			x->ValueType = TypeSInt32;
-		}
-		else if (x->ValueType == TypeState)
-		{
-			x = new FxCastStateToBool(x);
-			x = x->Resolve(ctx);
-		}
-		else
-		{
-			ScriptPosition.Message(MSG_ERROR, "Not an integral type");
-			delete this;
-			return NULL;
-		}
-	}
-	return x;
-}
-
 //==========================================================================
 //
 //
@@ -327,6 +295,104 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
 //
 //==========================================================================
 
+FxBoolCast::FxBoolCast(FxExpression *x)
+	: FxExpression(x->ScriptPosition)
+{
+	basex = x;
+	ValueType = TypeBool;
+}
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+FxBoolCast::~FxBoolCast()
+{
+	SAFE_DELETE(basex);
+}
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+FxExpression *FxBoolCast::Resolve(FCompileContext &ctx)
+{
+	CHECKRESOLVED();
+	SAFE_RESOLVE(basex, ctx);
+
+	if (basex->ValueType == TypeBool)
+	{
+		FxExpression *x = basex;
+		basex = nullptr;
+		delete this;
+		return x;
+	}
+	else if (basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER)
+	{
+		if (basex->isConstant())
+		{
+			assert(basex->ValueType != TypeState && "We shouldn't be able to generate a constant state ref");
+
+			ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
+			FxExpression *x = new FxConstant(constval.GetBool(), ScriptPosition);
+			delete this;
+			return x;
+		}
+		return this;
+	}
+	ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
+	delete this;
+	return nullptr;
+}
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build)
+{
+	ExpEmit from = basex->Emit(build);
+	assert(!from.Konst);
+	assert(basex->ValueType->GetRegType() == REGT_INT || basex->ValueType->GetRegType() == REGT_FLOAT || basex->ValueType->GetRegType() == REGT_POINTER);
+	ExpEmit to(build, REGT_INT);
+	from.Free(build);
+
+	// Preload result with 0.
+	build->Emit(OP_LI, to.RegNum, 0);
+
+	// Check source against 0.
+	if (from.RegType == REGT_INT)
+	{
+		build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum);
+	}
+	else if (from.RegType == REGT_FLOAT)
+	{
+		build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.));
+	}
+	else if (from.RegNum == REGT_POINTER)
+	{
+		build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
+	}
+	build->Emit(OP_JMP, 1);
+
+	// Reload result with 1 if the comparison fell through.
+	build->Emit(OP_LI, to.RegNum, 1);
+
+	return to;
+}
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
 FxIntCast::FxIntCast(FxExpression *x)
 : FxExpression(x->ScriptPosition)
 {
@@ -504,67 +570,6 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build)
 //
 //==========================================================================
 
-FxCastStateToBool::FxCastStateToBool(FxExpression *x)
-: FxExpression(x->ScriptPosition)
-{
-	basex = x;
-	ValueType = TypeSInt32;
-}
-
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-FxCastStateToBool::~FxCastStateToBool()
-{
-	SAFE_DELETE(basex);
-}
-
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-FxExpression *FxCastStateToBool::Resolve(FCompileContext &ctx)
-{
-	CHECKRESOLVED();
-	SAFE_RESOLVE(basex, ctx);
-
-	assert(basex->ValueType == TypeState);
-	assert(!basex->isConstant() && "We shouldn't be able to generate a constant state ref");
-	return this;
-}
-
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-ExpEmit FxCastStateToBool::Emit(VMFunctionBuilder *build)
-{
-	ExpEmit from = basex->Emit(build);
-	assert(from.RegType == REGT_POINTER);
-	from.Free(build);
-	ExpEmit to(build, REGT_INT);
-
-	// If from is NULL, produce 0. Otherwise, produce 1.
-	build->Emit(OP_LI, to.RegNum, 0);
-	build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC));
-	build->Emit(OP_JMP, 1);
-	build->Emit(OP_LI, to.RegNum, 1);
-	return to;
-}
-
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
 FxPlusSign::FxPlusSign(FxExpression *operand)
 : FxExpression(operand->ScriptPosition)
 {
@@ -765,10 +770,9 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
 
 ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build)
 {
-	assert(ValueType == Operand->ValueType);
-	assert(ValueType == TypeSInt32);
+	assert(Operand->ValueType->GetRegType() == REGT_INT);
 	ExpEmit from = Operand->Emit(build);
-	assert(from.Konst == 0);
+	assert(!from.Konst);
 	// Do it in-place.
 	build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
 	return from;
@@ -806,33 +810,23 @@ FxUnaryNotBoolean::~FxUnaryNotBoolean()
 FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
 {
 	CHECKRESOLVED();
-	if (Operand)
+	SAFE_RESOLVE(Operand, ctx);
+
+	if (Operand->ValueType != TypeBool)
 	{
-		Operand = Operand->ResolveAsBoolean(ctx);
-	}
-	if (!Operand)
-	{
-		delete this;
-		return NULL;
+		Operand = new FxBoolCast(Operand);
+		SAFE_RESOLVE(Operand, ctx);
 	}
 
-	if (Operand->IsNumeric() || Operand->IsPointer())
+	if (Operand->isConstant())
 	{
-		if (Operand->isConstant())
-		{
-			bool result = !static_cast<FxConstant *>(Operand)->GetValue().GetBool();
-			FxExpression *e = new FxConstant(result, ScriptPosition);
-			delete this;
-			return e;
-		}
-	}
-	else
-	{
-		ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
+		bool result = !static_cast<FxConstant *>(Operand)->GetValue().GetBool();
+		FxExpression *e = new FxConstant(result, ScriptPosition);
 		delete this;
-		return NULL;
+		return e;
 	}
-	ValueType = TypeSInt32;
+
+	ValueType = TypeBool;
 	return this;
 }
 
@@ -844,32 +838,14 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
 
 ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
 {
+	assert(Operand->ValueType == ValueType);
+	assert(ValueType == TypeBool);
 	ExpEmit from = Operand->Emit(build);
 	assert(!from.Konst);
-	ExpEmit to(build, REGT_INT);
-	from.Free(build);
-
-	// Preload result with 0.
-	build->Emit(OP_LI, to.RegNum, 0, 0);
-
-	// Check source against 0.
-	if (from.RegType == REGT_INT)
-	{
-		build->Emit(OP_EQ_R, 0, from.RegNum, to.RegNum);
-	}
-	else if (from.RegType == REGT_FLOAT)
-	{
-		build->Emit(OP_EQF_K, 0, from.RegNum, build->GetConstantFloat(0));
-	}
-	else if (from.RegNum == REGT_POINTER)
-	{
-		build->Emit(OP_EQA_K, 0, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC));
-	}
-	build->Emit(OP_JMP, 1);
-
-	// Reload result with 1 if the comparison fell through.
-	build->Emit(OP_LI, to.RegNum, 1);
-	return to;
+	// ~x & 1
+	build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
+	build->Emit(OP_AND_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
+	return from;
 }
 
 //==========================================================================
@@ -914,6 +890,10 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
 		return false;
 	}
 
+	if (left->ValueType == TypeBool && right->ValueType == TypeBool)
+	{
+		ValueType = TypeBool;
+	}
 	if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT)
 	{
 		ValueType = TypeSInt32;
@@ -1276,7 +1256,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
 		return e;
 	}
 	Promote(ctx);
-	ValueType = TypeSInt32;
+	ValueType = TypeBool;
 	return this;
 }
 
@@ -1327,7 +1307,7 @@ ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
 		op1.Free(build);
 	}
 
-	// See FxUnaryNotBoolean for comments, since it's the same thing.
+	// See FxBoolCast for comments, since it's the same thing.
 	build->Emit(OP_LI, to.RegNum, 0, 0);
 	build->Emit(instr, check, op1.RegNum, op2.RegNum);
 	build->Emit(OP_JMP, 1);
@@ -1392,7 +1372,7 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
 		return e;
 	}
 	Promote(ctx);
-	ValueType = TypeSInt32;
+	ValueType = TypeBool;
 	return this;
 }
 
@@ -1600,7 +1580,7 @@ FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r)
 	Operator=o;
 	left=l;
 	right=r;
-	ValueType = TypeSInt32;
+	ValueType = TypeBool;
 }
 
 //==========================================================================
@@ -1624,16 +1604,22 @@ FxBinaryLogical::~FxBinaryLogical()
 FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
 {
 	CHECKRESOLVED();
-	if (left) left = left->ResolveAsBoolean(ctx);
-	if (right) right = right->ResolveAsBoolean(ctx);
-	if (!left || !right)
+	RESOLVE(left, ctx);
+	RESOLVE(right, ctx);
+	ABORT(right && left);
+
+	if (left->ValueType != TypeBool)
 	{
-		delete this;
-		return NULL;
+		left = new FxBoolCast(left);
+		SAFE_RESOLVE(left, ctx);
+	}
+	if (right->ValueType != TypeBool)
+	{
+		right = new FxBoolCast(right);
+		SAFE_RESOLVE(right, ctx);
 	}
 
 	int b_left=-1, b_right=-1;
-
 	if (left->isConstant()) b_left = static_cast<FxConstant *>(left)->GetValue().GetBool();
 	if (right->isConstant()) b_right = static_cast<FxConstant *>(right)->GetValue().GetBool();
 
@@ -1643,13 +1629,13 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
 	{
 		if (b_left==0 || b_right==0)
 		{
-			FxExpression *x = new FxConstant(0, ScriptPosition);
+			FxExpression *x = new FxConstant(true, ScriptPosition);
 			delete this;
 			return x;
 		}
 		else if (b_left==1 && b_right==1)
 		{
-			FxExpression *x = new FxConstant(1, ScriptPosition);
+			FxExpression *x = new FxConstant(false, ScriptPosition);
 			delete this;
 			return x;
 		}
@@ -1672,13 +1658,13 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
 	{
 		if (b_left==1 || b_right==1)
 		{
-			FxExpression *x = new FxConstant(1, ScriptPosition);
+			FxExpression *x = new FxConstant(true, ScriptPosition);
 			delete this;
 			return x;
 		}
 		if (b_left==0 && b_right==0)
 		{
-			FxExpression *x = new FxConstant(0, ScriptPosition);
+			FxExpression *x = new FxConstant(false, ScriptPosition);
 			delete this;
 			return x;
 		}
@@ -1697,14 +1683,6 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
 			return x;
 		}
 	}
-	if (left->ValueType->GetRegType() != REGT_INT)
-	{
-		left = new FxIntCast(left);
-	}
-	if (right->ValueType->GetRegType() != REGT_INT)
-	{
-		right = new FxIntCast(right);
-	}
 	return this;
 }
 
@@ -1804,17 +1782,25 @@ FxConditional::~FxConditional()
 FxExpression *FxConditional::Resolve(FCompileContext& ctx)
 {
 	CHECKRESOLVED();
-	if (condition) condition = condition->ResolveAsBoolean(ctx);
+	RESOLVE(condition, ctx);
 	RESOLVE(truex, ctx);
 	RESOLVE(falsex, ctx);
 	ABORT(condition && truex && falsex);
 
-	if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT)
+	if (truex->ValueType == TypeBool && falsex->ValueType == TypeBool)
+		ValueType = TypeBool;
+	else if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT)
 		ValueType = TypeSInt32;
 	else if (truex->IsNumeric() && falsex->IsNumeric())
 		ValueType = TypeFloat64;
 	//else if (truex->ValueType != falsex->ValueType)
 
+	if (condition->ValueType != TypeBool)
+	{
+		condition = new FxBoolCast(condition);
+		SAFE_RESOLVE(condition, ctx);
+	}
+
 	if (condition->isConstant())
 	{
 		ExpVal condval = static_cast<FxConstant *>(condition)->GetValue();
@@ -3735,23 +3721,32 @@ FxIfStatement::~FxIfStatement()
 FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
 {
 	CHECKRESOLVED();
-	if (WhenTrue == NULL && WhenFalse == NULL)
+
+	if (WhenTrue == nullptr && WhenFalse == nullptr)
 	{ // We don't do anything either way, so disappear
 		delete this;
-		return NULL;
+		return nullptr;
 	}
-	Condition = Condition->ResolveAsBoolean(ctx);
-	ABORT(Condition);
-	if (WhenTrue != NULL)
+
+	SAFE_RESOLVE(Condition, ctx);
+
+	if (Condition->ValueType != TypeBool)
+	{
+		Condition = new FxBoolCast(Condition);
+		SAFE_RESOLVE(Condition, ctx);
+	}
+
+	if (WhenTrue != nullptr)
 	{
 		WhenTrue = WhenTrue->Resolve(ctx);
 		ABORT(WhenTrue);
 	}
-	if (WhenFalse != NULL)
+	if (WhenFalse != nullptr)
 	{
 		WhenFalse = WhenFalse->Resolve(ctx);
 		ABORT(WhenFalse);
 	}
+
 	ValueType = TypeVoid;
 
 	if (Condition->isConstant())
@@ -3766,6 +3761,7 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
 		delete this;
 		return e;
 	}
+
 	return this;
 }
 

From af53f5a825ae1fa1d3f109f54d4bb6e55fc5ce2b Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Wed, 6 Jul 2016 00:32:26 +0200
Subject: [PATCH 29/63] Properly use the boolean type in function declarations

This will get rid of useless casts like 'if (isPointerEqual(x))'
It will also allow for proper casting in parameters like using a state as a boolean which is allowed in if statements for example
---
 src/thingdef/thingdef_parse.cpp | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp
index e4488de45..c97930277 100644
--- a/src/thingdef/thingdef_parse.cpp
+++ b/src/thingdef/thingdef_parse.cpp
@@ -77,7 +77,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
 		sc.MustGetString();
 		x = new FxConstant(FSoundID(sc.String), sc);
 	}
-	else if (type == TypeSInt32 || type == TypeFloat64)
+	else if (type == TypeBool || type == TypeSInt32 || type == TypeFloat64)
 	{
 		x = ParseExpression (sc, cls, constant);
 		if (constant && !x->isConstant())
@@ -85,8 +85,12 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
 			sc.ScriptMessage("Default parameter must be constant.");
 			FScriptPosition::ErrorCounter++;
 		}
-		// Do automatic coercion between ints and floats.
-		if (type == TypeSInt32)
+		// Do automatic coercion between bools, ints and floats.
+		if (type == TypeBool)
+		{
+			x = new FxBoolCast(x);
+		}
+		else if (type == TypeSInt32)
 		{
 			x = new FxIntCast(x);
 		}
@@ -306,6 +310,9 @@ static void ParseArgListDef(FScanner &sc, PClassActor *cls,
 			switch (sc.TokenType)
 			{
 			case TK_Bool:
+				type = TypeBool;
+				break;
+
 			case TK_Int:
 				type = TypeSInt32;
 				break;
@@ -477,8 +484,11 @@ static void ParseNativeFunction(FScanner &sc, PClassActor *cls)
 	sc.MustGetAnyToken();
 	switch (sc.TokenType)
 	{
-	case TK_Int:
 	case TK_Bool:
+		rets.Push(TypeBool);
+		break;
+
+	case TK_Int:
 		rets.Push(TypeSInt32);
 		break;
 
@@ -1064,7 +1074,11 @@ static void ParseActionDef (FScanner &sc, PClassActor *cls)
 	// check for a return value
 	do
 	{
-		if (sc.CheckToken(TK_Int) || sc.CheckToken(TK_Bool))
+		if (sc.CheckToken(TK_Bool))
+		{
+			rets.Push(TypeBool);
+		}
+		else if (sc.CheckToken(TK_Int))
 		{
 			rets.Push(TypeSInt32);
 		}

From bbdc64a955eb3b438bb8dc6acc689fe5c49d1875 Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Fri, 8 Jul 2016 18:39:18 +0200
Subject: [PATCH 30/63] Fixed bad serialization of float types

The value was written twice if it couldn't be reduced to a single precision value
---
 src/dobjtype.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp
index 6b963f6d4..a7f07247f 100644
--- a/src/dobjtype.cpp
+++ b/src/dobjtype.cpp
@@ -1272,6 +1272,7 @@ void PFloat::WriteValue(FArchive &ar, const void *addr) const
 		{
 			ar.WriteByte(VAL_Float64);
 			ar << doubleprecision;
+			return;
 		}
 	}
 	else

From bdeb2338498840918cb581e8d1ab47235af3ca5c Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Mon, 4 Jul 2016 19:54:26 +0200
Subject: [PATCH 31/63] Fixed: conditionals didn't properly compile to vm code

---
 src/thingdef/thingdef_expression.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp
index 463156d7f..b4a0b3fda 100644
--- a/src/thingdef/thingdef_expression.cpp
+++ b/src/thingdef/thingdef_expression.cpp
@@ -1838,6 +1838,7 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx)
 
 ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
 {
+	size_t truejump, falsejump;
 	ExpEmit out;
 
 	// The true and false expressions ought to be assigned to the
@@ -1848,7 +1849,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
 
 	// Test condition.
 	build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0));
-	size_t patchspot = build->Emit(OP_JMP, 0);
+	falsejump = build->Emit(OP_JMP, 0);
 
 	// Evaluate true expression.
 	if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT)
@@ -1872,9 +1873,11 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
 			out = trueop;
 		}
 	}
+	// Make sure to skip the false path.
+	truejump = build->Emit(OP_JMP, 0);
 
 	// Evaluate false expression.
-	build->BackpatchToHere(patchspot);
+	build->BackpatchToHere(falsejump);
 	if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT)
 	{
 		build->EmitLoadInt(out.RegNum, static_cast<FxConstant *>(falsex)->GetValue().GetInt());
@@ -1904,6 +1907,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
 			}
 		}
 	}
+	build->BackpatchToHere(truejump);
 
 	return out;
 }

From 79264cb8cd5a08d852a45b57f016cd672fd3f174 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Tue, 12 Jul 2016 19:57:32 +0200
Subject: [PATCH 32/63] - fixed missing QuakeEx parameter conversion.

---
 src/p_acs.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index 7cbfd69b4..919834a06 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -5712,8 +5712,8 @@ doplaysound:			if (funcIndex == ACSF_PlayActorSound)
 				argCount > 11 ? ACSToDouble(args[11]) : 1.0,
 				argCount > 12 ? args[12] : 0,
 				argCount > 13 ? args[13] : 0,
-				argCount > 14 ? args[14] : 0,
-				argCount > 15 ? args[15] : 0);
+				argCount > 14 ? ACSToDouble(args[14]) : 0,
+				argCount > 15 ? ACSToDouble(args[15]) : 0);
 		}
 
 		case ACSF_SetLineActivation:

From 522b2f4706a8a67b40ebc2f1e4332b3257faf7ae Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Tue, 12 Jul 2016 23:50:45 +0200
Subject: [PATCH 33/63] - updated xlat/eternity.txt for reference.

---
 wadsrc/static/xlat/eternity.txt | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt
index bc5159d11..4db96f2da 100644
--- a/wadsrc/static/xlat/eternity.txt
+++ b/wadsrc/static/xlat/eternity.txt
@@ -234,3 +234,20 @@ enum
 447 = 0, Exit_Normal(0)
 448 = 0, Exit_Secret(0)
 449 = 0, Teleport_NewMap(0)
+450 = 0, Line_Horizon(0)
+451 = 0, Floor_RaiseAndCrush(0)
+452 = 0, Floor_CrushStop(0)
+453 = 0, FloorAndCeiling_LowerByValue(0)
+454 = 0, FloorAndCeiling_RaiseByValue(0)
+457 = 0, Door_LockedOpen(0)
+458 = 0, Elevator_RaiseToNearest(0)
+459 = 0, Elevator_LowerToNearest(0)
+460 = 0, Elevator_MoveToFloor(0)
+461 = 0, Light_MaxNeighbor(0)
+462 = 0, ChangeSkill(0)
+463 = 0, Light_StrobeDoom(0)
+464 = 0, Generic_Floor(0)
+465 = 0, Generic_Ceiling(0)
+466 = 0, Floor_TransferTrigger(0)
+467 = 0, Floor_TransferNumeric(0)
+468 = 0, FloorAndCeiling_LowerRaise(0)

From 1cf51791de7aec5d0555a65a01c4051164ef3646 Mon Sep 17 00:00:00 2001
From: m-x-d <j.maxed@gmail.com>
Date: Wed, 13 Jul 2016 00:27:59 +0300
Subject: [PATCH 34/63] Adds //%Title property to all locks to make parsing
 LOCKDEFS by map editors more feasible. Fixes: Strife Base key Message now
 uses LANGUAGE string.

---
 wadsrc/static/lockdefs.txt | 74 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 73 insertions(+), 1 deletion(-)

diff --git a/wadsrc/static/lockdefs.txt b/wadsrc/static/lockdefs.txt
index 2167f935d..04e490224 100644
--- a/wadsrc/static/lockdefs.txt
+++ b/wadsrc/static/lockdefs.txt
@@ -5,6 +5,7 @@ ClearLocks
 
 Lock 1 Doom
 {
+	//$Title "Red key card"
 	RedCard
 	Message "$PD_REDC"
 	RemoteMessage "$PD_REDCO"
@@ -14,6 +15,7 @@ Lock 1 Doom
 
 Lock 2 Doom
 {
+	//$Title "Blue key card"
 	BlueCard
 	Message "$PD_BLUEC"
 	RemoteMessage "$PD_BLUECO"
@@ -23,6 +25,7 @@ Lock 2 Doom
 
 Lock 3 Doom
 {
+	//$Title "Yellow key card"
 	YellowCard
 	Message "$PD_YELLOWC"
 	RemoteMessage "$PD_YELLOWCO"
@@ -32,6 +35,7 @@ Lock 3 Doom
 
 Lock 4 Doom
 {
+	//$Title "Red skull"
 	RedSkull
 	Message "$PD_REDS"
 	RemoteMessage "$PD_REDSO"
@@ -41,6 +45,7 @@ Lock 4 Doom
 
 Lock 5 Doom
 {
+	//$Title "Blue skull"
 	BlueSkull
 	Message "$PD_BLUES"
 	RemoteMessage "$PD_BLUESO"
@@ -50,6 +55,7 @@ Lock 5 Doom
 
 Lock 6 Doom
 {
+	//$Title "Yellow skull"
 	YellowSkull
 	Message "$PD_YELLOWS"
 	RemoteMessage "$PD_YELLOWSO"
@@ -59,6 +65,7 @@ Lock 6 Doom
 
 Lock 129 Doom
 {
+	//$Title "Any red key"
 	Any { RedCard RedSkull KeyGreen }
 	Message "$PD_REDK"
 	RemoteMessage "$PD_REDO"
@@ -68,6 +75,7 @@ Lock 129 Doom
 
 Lock 130 Doom
 {
+	//$Title "Any blue key"
 	Any { BlueCard BlueSkull KeyBlue }
 	Message "$PD_BLUEK"
 	RemoteMessage "$PD_BLUEO"
@@ -77,6 +85,7 @@ Lock 130 Doom
 
 Lock 131 Doom
 {
+	//$Title "Any yellow key"
 	Any { YellowCard YellowSkull KeyYellow }
 	Message "$PD_YELLOWK"
 	RemoteMessage "$PD_YELLOWO"
@@ -86,6 +95,7 @@ Lock 131 Doom
 
 Lock 132 Doom
 {
+	//$Title "Red card or skull"
 	Any { RedCard RedSkull }
 	Message "$PD_REDK"
 	RemoteMessage "$PD_REDO"
@@ -95,6 +105,7 @@ Lock 132 Doom
 
 Lock 133 Doom
 {
+	//$Title "Blue card or skull"
 	Any { BlueCard BlueSkull }
 	Message "$PD_BLUEK"
 	RemoteMessage "$PD_BLUEO"
@@ -104,6 +115,7 @@ Lock 133 Doom
 
 Lock 134 Doom
 {
+	//$Title "Yellow card or skull"
 	Any { YellowCard YellowSkull }
 	Message "$PD_YELLOWK"
 	RemoteMessage "$PD_YELLOWO"
@@ -112,6 +124,7 @@ Lock 134 Doom
 
 Lock 100
 {
+	//$Title "Any key"
 	Message "$PD_ANY"
 	RemoteMessage "$PD_ANYOBJ"
 	Mapcolor 128 128 255
@@ -119,6 +132,7 @@ Lock 100
 
 Lock 228
 {
+	//$Title "Any key"
 	Message "$PD_ANY"
 	RemoteMessage "$PD_ANYOBJ"
 	Mapcolor 128 128 255
@@ -126,6 +140,7 @@ Lock 228
 
 Lock 229 Doom
 {
+	//$Title "One of each color"
 	Any { BlueCard BlueSkull KeyBlue}
 	Any { YellowCard YellowSkull KeyYellow}
 	Any { RedCard RedSkull KeyGreen}
@@ -135,6 +150,7 @@ Lock 229 Doom
 
 Lock 101 Doom
 {
+	//$Title "All keys"
 	BlueCard 
 	BlueSkull
 	YellowCard 
@@ -151,6 +167,7 @@ Lock 101 Doom
 
 Lock 1 Heretic
 {
+	//$Title "Green key"
 	KeyGreen
 	Message "$TXT_NEEDGREENKEY"
 	Mapcolor 0 255 0
@@ -159,6 +176,7 @@ Lock 1 Heretic
 
 Lock 2 Heretic
 {
+	//$Title "Blue key"
 	KeyBlue 
 	Message "$TXT_NEEDBLUEKEY"
 	Mapcolor 0 0 255
@@ -167,6 +185,7 @@ Lock 2 Heretic
 
 Lock 3 Heretic
 {
+	//$Title "Yellow key"
 	KeyYellow
 	Message "$TXT_NEEDYELLOWKEY"
 	Mapcolor 255 255 0
@@ -175,6 +194,7 @@ Lock 3 Heretic
 
 Lock 129 Heretic
 {
+	//$Title "Green key"
 	KeyGreen
 	Message "$TXT_NEEDGREENKEY"
 	Mapcolor 0 255 0
@@ -183,6 +203,7 @@ Lock 129 Heretic
 
 Lock 130 Heretic
 {
+	//$Title "Blue key"
 	KeyBlue 
 	Message "$TXT_NEEDBLUEKEY"
 	Mapcolor 0 0 255
@@ -191,6 +212,7 @@ Lock 130 Heretic
 
 Lock 131 Heretic
 {
+	//$Title "Yellow key"
 	KeyYellow
 	Message "$TXT_NEEDYELLOWKEY"
 	Mapcolor 255 255 0
@@ -199,6 +221,7 @@ Lock 131 Heretic
 
 Lock 229 Heretic
 {
+	//$Title "All keys"
 	KeyGreen 
 	KeyYellow 
 	KeyBlue
@@ -208,6 +231,7 @@ Lock 229 Heretic
 
 Lock 101 Heretic
 {
+	//$Title "All keys"
 	KeyGreen 
 	KeyYellow 
 	KeyBlue
@@ -222,6 +246,7 @@ Lock 101 Heretic
 
 Lock 1 Hexen
 {
+	//$Title "Steel key"
 	KeySteel
 	Message "$TXT_NEED_KEY_STEEL"
 	Mapcolor 150 150 150
@@ -230,6 +255,7 @@ Lock 1 Hexen
 
 Lock 2 Hexen
 {
+	//$Title "Cave key"
 	KeyCave
 	Message "$TXT_NEED_KEY_CAVE"
 	Mapcolor 255 218 0
@@ -238,6 +264,7 @@ Lock 2 Hexen
 
 Lock 3 Hexen
 {
+	//$Title "Axe key"
 	KeyAxe
 	Message "$TXT_NEED_KEY_AXE"
 	Mapcolor 64 64 255
@@ -246,6 +273,7 @@ Lock 3 Hexen
 
 Lock 4 Hexen
 {
+	//$Title "Fire key"
 	KeyFire
 	Message "$TXT_NEED_KEY_FIRE"
 	Mapcolor 255 128 0
@@ -254,6 +282,7 @@ Lock 4 Hexen
 
 Lock 5 Hexen
 {
+	//$Title "Emerald key"
 	KeyEmerald
 	Message "$TXT_NEED_KEY_EMERALD"
 	Mapcolor 0 255 0
@@ -262,6 +291,7 @@ Lock 5 Hexen
 
 Lock 6 Hexen
 {
+	//$Title "Dungeon key"
 	KeyDungeon
 	Message "$TXT_NEED_KEY_DUNGEON"
 	Mapcolor 47 151 255
@@ -270,6 +300,7 @@ Lock 6 Hexen
 
 Lock 7 Hexen
 {
+	//$Title "Silver key"
 	KeySilver
 	Message "$TXT_NEED_KEY_SILVER"
 	Mapcolor 154 152 188
@@ -278,6 +309,7 @@ Lock 7 Hexen
 
 Lock 8 Hexen
 {
+	//$Title "Rusted key"
 	KeyRusted
 	Message "$TXT_NEED_KEY_RUSTED"
 	Mapcolor 156 76 0
@@ -286,6 +318,7 @@ Lock 8 Hexen
 
 Lock 9 Hexen
 {
+	//$Title "Horn key"
 	KeyHorn
 	Message "$TXT_NEED_KEY_HORN"
 	Mapcolor 255 218 0
@@ -294,6 +327,7 @@ Lock 9 Hexen
 
 Lock 10 Hexen
 {
+	//$Title "Swamp key"
 	KeySwamp
 	Message "$TXT_NEED_KEY_SWAMP"
 	Mapcolor 64 255 64
@@ -302,6 +336,7 @@ Lock 10 Hexen
 
 Lock 11 Hexen
 {
+	//$Title "Castle key"
 	KeyCastle
 	Message "$TXT_NEED_KEY_CASTLE"
 	Mapcolor 255 64 64
@@ -310,6 +345,7 @@ Lock 11 Hexen
 
 Lock 101 Hexen
 {
+	//$Title "All keys"
 	KeySteel
 	KeyCave
 	KeyAxe
@@ -326,6 +362,7 @@ Lock 101 Hexen
 
 Lock 229 Hexen
 {
+	//$Title "All keys"
 	KeySteel
 	KeyCave
 	KeyAxe
@@ -345,14 +382,16 @@ Lock 229 Hexen
 
 Lock 1 Strife
 {
+	//$Title "Base key"
 	BaseKey
-	Message "You don't have the key"
+	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
 }
 
 
 Lock 2 Strife
 {
+	//$Title "Governor's key"
 	GovsKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -361,6 +400,7 @@ Lock 2 Strife
 
 Lock 3 Strife
 {
+	//$Title "Travel passcard"
 	Passcard
 	RemoteMessage "$TXT_NEED_PASSCARD"
 	Message "$TXT_NEED_PASSCARD_DOOR"
@@ -370,6 +410,7 @@ Lock 3 Strife
 
 Lock 4 Strife
 {
+	//$Title "ID badge"
 	IDBadge
 	Message "$TXT_NEED_IDCARD"
 	Mapcolor 255 128 0
@@ -378,6 +419,7 @@ Lock 4 Strife
 
 Lock 5 Strife
 {
+	//$Title "Prison key"
 	PrisonKey
 	Message "$TXT_NEED_PRISONKEY"
 	Mapcolor 0 255 0
@@ -386,6 +428,7 @@ Lock 5 Strife
 
 Lock 6 Strife
 {
+	//$Title "Severed hand"
 	SeveredHand
 	Message "$TXT_NEED_HANDPRINT"
 	Mapcolor 255 151 100
@@ -394,6 +437,7 @@ Lock 6 Strife
 
 Lock 7 Strife
 {
+	//$Title "Power key 1"
 	Power1Key
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -402,6 +446,7 @@ Lock 7 Strife
 
 Lock 8 Strife
 {
+	//$Title "Power key 2"
 	Power2Key
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -410,6 +455,7 @@ Lock 8 Strife
 
 Lock 9 Strife
 {
+	//$Title "Power key 3"
 	Power3Key
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -418,6 +464,7 @@ Lock 9 Strife
 
 Lock 10 Strife
 {
+	//$Title "Gold key"
 	GoldKey
 	Message "$TXT_NEED_GOLDKEY"
 	Mapcolor 255 200 0
@@ -426,6 +473,7 @@ Lock 10 Strife
 
 Lock 11 Strife
 {
+	//$Title "ID card"
 	IDCard
 	RemoteMessage "$TXT_NEED_IDBADGE"
 	Message "$TXT_NEED_IDBADGE_DOOR"
@@ -434,6 +482,7 @@ Lock 11 Strife
 
 Lock 12 Strife
 {
+	//$Title "Silver key"
 	SilverKey
 	Message "$TXT_NEED_SILVERKEY"
 	Mapcolor 150 150 150
@@ -441,6 +490,7 @@ Lock 12 Strife
 
 Lock 13 Strife
 {
+	//$Title "Oracle key"
 	OracleKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -448,6 +498,7 @@ Lock 13 Strife
 
 Lock 14 Strife
 {
+	//$Title "Military key"
 	MilitaryID
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -455,6 +506,7 @@ Lock 14 Strife
 
 Lock 15 Strife
 {
+	//$Title "Order key"
 	OrderKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -462,6 +514,7 @@ Lock 15 Strife
 
 Lock 16 Strife
 {
+	//$Title "Warehouse key"
 	WarehouseKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -469,6 +522,7 @@ Lock 16 Strife
 
 Lock 17 Strife
 {
+	//$Title "Brass key"
 	BrassKey
 	Message "$TXT_NEED_BRASSKEY"
 	Mapcolor 150 75 0
@@ -476,6 +530,7 @@ Lock 17 Strife
 
 Lock 18 Strife
 {
+	//$Title "Red crystal key"
 	RedCrystalKey
 	Message "$TXT_NEED_REDCRYSTAL"
 	Mapcolor 150 150 150
@@ -483,6 +538,7 @@ Lock 18 Strife
 
 Lock 19 Strife
 {
+	//$Title "Blue crystal key"
 	BlueCrystalKey
 	Message "$TXT_NEED_BLUECRYSTAL"
 	Mapcolor 150 150 150
@@ -490,6 +546,7 @@ Lock 19 Strife
 
 Lock 20 Strife
 {
+	//$Title "Chapel key"
 	ChapelKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -497,6 +554,7 @@ Lock 20 Strife
 
 Lock 21 Strife
 {
+	//$Title "Catacomb key"
 	CatacombKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -504,6 +562,7 @@ Lock 21 Strife
 
 Lock 22 Strife
 {
+	//$Title "Security key"
 	SecurityKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -511,6 +570,7 @@ Lock 22 Strife
 
 Lock 23 Strife
 {
+	//$Title "Core key"
 	CoreKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -518,6 +578,7 @@ Lock 23 Strife
 
 Lock 24 Strife
 {
+	//$Title "Mauler key"
 	MaulerKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -525,6 +586,7 @@ Lock 24 Strife
 
 Lock 25 Strife
 {
+	//$Title "Factory key"
 	FactoryKey
 	Message "$TXT_NEEDKEY"
  	Mapcolor 150 150 150
@@ -532,6 +594,7 @@ Lock 25 Strife
 
 Lock 26 Strife
 {
+	//$Title "Mine key"
 	MineKey
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -539,6 +602,7 @@ Lock 26 Strife
 
 Lock 27 Strife
 {
+	//$Title "New key 5"
 	NewKey5
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -546,6 +610,7 @@ Lock 27 Strife
 
 Lock 50 Strife
 {
+	//$Title "Prison key"
 	PrisonPass
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -553,6 +618,7 @@ Lock 50 Strife
 
 Lock 51 Strife
 {
+	//$Title "Oracle pass"
 	OraclePass
 	Message "$TXT_NEEDKEY"
 	Mapcolor 150 150 150
@@ -564,6 +630,7 @@ Lock 51 Strife
 
 Lock 1 Chex
 {
+	//$Title "Red key card"
 	ChexRedCard
 	Message "$PD_REDC"
 	RemoteMessage "$PD_REDCO"
@@ -573,6 +640,7 @@ Lock 1 Chex
 
 Lock 2 Chex
 {
+	//$Title "Blue key card"
 	ChexBlueCard
 	Message "$PD_BLUEC"
 	RemoteMessage "$PD_BLUECO"
@@ -582,6 +650,7 @@ Lock 2 Chex
 
 Lock 3 Chex
 {
+	//$Title "Yellow key card"
 	ChexYellowCard
 	Message "$PD_YELLOWC"
 	RemoteMessage "$PD_YELLOWCO"
@@ -590,6 +659,7 @@ Lock 3 Chex
 
 Lock 129 Chex
 {
+	//$Title "Red key"
 	ChexRedCard
 	Message "$PD_REDK"
 	RemoteMessage "$PD_REDO"
@@ -599,6 +669,7 @@ Lock 129 Chex
 
 Lock 130 Chex
 {
+	//$Title "Blue key"
 	ChexBlueCard
 	Message "$PD_BLUEK"
 	RemoteMessage "$PD_BLUEO"
@@ -608,6 +679,7 @@ Lock 130 Chex
 
 Lock 131 Chex
 {
+	//$Title "Yellow key"
 	ChexYellowCard
 	Message "$PD_YELLOWK"
 	RemoteMessage "$PD_YELLOWO"

From 7ded355d5dde1c3f396a9562e8d7356c40fb7cda Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Mon, 4 Jul 2016 13:58:49 -0500
Subject: [PATCH 35/63] Added rollcenter compatibility.

---
 src/actor.h                    | 1 +
 src/thingdef/thingdef_data.cpp | 1 +
 2 files changed, 2 insertions(+)

diff --git a/src/actor.h b/src/actor.h
index 30c4e842a..93d2834a8 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -412,6 +412,7 @@ enum ActorRenderFlag
 	RF_INVISIBLE		= 0x8000,	// Don't bother drawing this actor
 	RF_ROLLSPRITE		= 0x40000,	//[marrub]roll the sprite billboard
 	RF_DONTFLIP			= 0x80000,	// Don't flip it when viewed from behind.
+	RF_ROLLCENTER		= 0x100000, // Rotate from the center of sprite instead of offsets
 
 	RF_FORCEYBILLBOARD		= 0x10000,	// [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting)
 	RF_FORCEXYBILLBOARD		= 0x20000,	// [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting)
diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp
index b9e6414ff..a86e98566 100644
--- a/src/thingdef/thingdef_data.cpp
+++ b/src/thingdef/thingdef_data.cpp
@@ -270,6 +270,7 @@ static FFlagDef ActorFlagDefs[]=
 	DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
 	DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
 	DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags),
+	DEFINE_FLAG(RF, ROLLCENTER, AActor, renderflags),
 
 	// Bounce flags
 	DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),

From 75cb8c00a67dc97720903c11e3bd7db037fef83b Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Sat, 18 Jun 2016 11:29:02 +0200
Subject: [PATCH 36/63] Fixed: the flags weren't properly reset if a mod used
 the old layers before the code used them

---
 src/p_pspr.cpp | 10 +++++++---
 src/p_pspr.h   |  2 +-
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp
index e63490110..87afc64fc 100644
--- a/src/p_pspr.cpp
+++ b/src/p_pspr.cpp
@@ -216,14 +216,18 @@ DPSprite *player_t::GetPSprite(PSPLayers layer)
 	}
 
 	// Always update the caller here in case we switched weapon
-	// or if the layer was being used by an inventory item before.
+	// or if the layer was being used by something else before.
 	pspr->Caller = newcaller;
 
 	if (newcaller != oldcaller)
-	{ // Only change the flags if this layer was created now or if we updated the caller.
+	{ // Only reset flags if this layer was created now or if it was being used before.
 		if (layer >= PSP_TARGETCENTER)
 		{ // The targeter layers were affected by those.
-			pspr->Flags |= (PSPF_CVARFAST|PSPF_POWDOUBLE);
+			pspr->Flags = (PSPF_CVARFAST|PSPF_POWDOUBLE);
+		}
+		else
+		{
+			pspr->Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_CVARFAST|PSPF_POWDOUBLE);
 		}
 	}
 
diff --git a/src/p_pspr.h b/src/p_pspr.h
index 2c7a36518..a7cf49f8c 100644
--- a/src/p_pspr.h
+++ b/src/p_pspr.h
@@ -42,7 +42,7 @@ class FArchive;
 // drawn directly on the view screen,
 // coordinates are given for a 320*200 view screen.
 //
-enum PSPLayers // These are all called by the owner's ReadyWeapon.
+enum PSPLayers
 {
 	PSP_STRIFEHANDS = -1,
 	PSP_WEAPON = 1,

From da6e12d5bc736ed5a8a0097e396c4fd462e2875b Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Fri, 8 Jul 2016 11:13:58 +0200
Subject: [PATCH 37/63] Fixed: the weapon layer offsets were interpolated even
 after the player switched his weapon

---
 src/p_pspr.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp
index 87afc64fc..148c788fa 100644
--- a/src/p_pspr.cpp
+++ b/src/p_pspr.cpp
@@ -220,7 +220,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer)
 	pspr->Caller = newcaller;
 
 	if (newcaller != oldcaller)
-	{ // Only reset flags if this layer was created now or if it was being used before.
+	{ // Only reset stuff if this layer was created now or if it was being used before.
 		if (layer >= PSP_TARGETCENTER)
 		{ // The targeter layers were affected by those.
 			pspr->Flags = (PSPF_CVARFAST|PSPF_POWDOUBLE);
@@ -229,6 +229,9 @@ DPSprite *player_t::GetPSprite(PSPLayers layer)
 		{
 			pspr->Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_CVARFAST|PSPF_POWDOUBLE);
 		}
+
+		pspr->oldx = pspr->x;
+		pspr->oldy = pspr->y;
 	}
 
 	return pspr;

From b8e1bead0a9d36f389041deba15f03ef0b2a10e4 Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Sat, 18 Jun 2016 09:38:22 +0200
Subject: [PATCH 38/63] Removed unneeded checks

GetPSprite cannot return a null pointer and calling setstate with a null pointer destroys it
---
 src/g_strife/a_strifestuff.cpp | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp
index 4e49121fa..8f571328b 100644
--- a/src/g_strife/a_strifestuff.cpp
+++ b/src/g_strife/a_strifestuff.cpp
@@ -352,22 +352,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns)
 
 	if (self->player != nullptr && self->player->mo == self)
 	{
-		FState *firehands = self->FindState("FireHands");
-		if (firehands != NULL)
-		{
-			DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS);
-			if (psp != nullptr)
-			{
-				psp->SetState(firehands);
-				psp->Flags &= PSPF_ADDWEAPON | PSPF_ADDBOB;
-				psp->y = WEAPONTOP;
-			}
+		DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS);
+		psp->Flags &= PSPF_ADDWEAPON | PSPF_ADDBOB;
+		psp->y = WEAPONTOP;
+		psp->SetState(self->FindState("FireHands"));
 
-			self->player->ReadyWeapon = nullptr;
-			self->player->PendingWeapon = WP_NOCHANGE;
-			self->player->playerstate = PST_LIVE;
-			self->player->extralight = 3;
-		}
+		self->player->ReadyWeapon = nullptr;
+		self->player->PendingWeapon = WP_NOCHANGE;
+		self->player->playerstate = PST_LIVE;
+		self->player->extralight = 3;
 	}
 	return 0;
 }

From 3ea70980f97a25bbcdb8dc213e7564f2a215841b Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Sat, 18 Jun 2016 09:46:55 +0200
Subject: [PATCH 39/63] Fixed: the strife firehands were interpolated if a mod
 used the layer before them

The flags were also already reset, no need to do it twice
---
 src/g_strife/a_strifestuff.cpp | 5 +----
 src/p_pspr.cpp                 | 4 ++++
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp
index 8f571328b..c0e280762 100644
--- a/src/g_strife/a_strifestuff.cpp
+++ b/src/g_strife/a_strifestuff.cpp
@@ -352,10 +352,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns)
 
 	if (self->player != nullptr && self->player->mo == self)
 	{
-		DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS);
-		psp->Flags &= PSPF_ADDWEAPON | PSPF_ADDBOB;
-		psp->y = WEAPONTOP;
-		psp->SetState(self->FindState("FireHands"));
+		P_SetPsprite(self->player, PSP_STRIFEHANDS, self->FindState("FireHands"));
 
 		self->player->ReadyWeapon = nullptr;
 		self->player->PendingWeapon = WP_NOCHANGE;
diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp
index 148c788fa..94a0084dd 100644
--- a/src/p_pspr.cpp
+++ b/src/p_pspr.cpp
@@ -229,6 +229,10 @@ DPSprite *player_t::GetPSprite(PSPLayers layer)
 		{
 			pspr->Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_CVARFAST|PSPF_POWDOUBLE);
 		}
+		if (layer == PSP_STRIFEHANDS)
+		{
+			pspr->y = WEAPONTOP;
+		}
 
 		pspr->oldx = pspr->x;
 		pspr->oldy = pspr->y;

From 05d1df3571c5a0023529d1bf878facd2f96ca517 Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Sat, 18 Jun 2016 10:48:13 +0200
Subject: [PATCH 40/63] Fixed crashes with the A_CrispyPlayer and A_HandLower
 action functions

Simply using FindPSprite in those functions wouldn't be enough because if a mod is using the firehands layer when they are called this would go very wrong
---
 src/g_strife/a_strifestuff.cpp | 25 ++++++++++++++++++++-----
 src/p_pspr.cpp                 |  3 +++
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp
index c0e280762..4533016ec 100644
--- a/src/g_strife/a_strifestuff.cpp
+++ b/src/g_strife/a_strifestuff.cpp
@@ -378,14 +378,22 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer)
 
 	if (self->player != nullptr && self->player->mo == self)
 	{
-		self->player->playerstate = PST_DEAD;
-
 		DPSprite *psp;
 		psp = self->player->GetPSprite(PSP_STRIFEHANDS);
+
 		FState *firehandslower = self->FindState("FireHandsLower");
 		FState *firehands = self->FindState("FireHands");
-		if (firehandslower != NULL && firehands != NULL && firehands < firehandslower)
-			psp->SetState(psp->GetState() + (firehandslower - firehands));
+		FState *state = psp->GetState();
+
+		if (state != nullptr && firehandslower != nullptr && firehands != nullptr && firehands < firehandslower)
+		{
+			self->player->playerstate = PST_DEAD;
+			psp->SetState(state + (firehandslower - firehands));
+		}
+		else if (state == nullptr)
+		{
+			psp->SetState(nullptr);
+		}
 	}
 	return 0;
 }
@@ -397,13 +405,20 @@ DEFINE_ACTION_FUNCTION(AActor, A_HandLower)
 	if (self->player != nullptr)
 	{
 		DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS);
+
+		if (psp->GetState() == nullptr)
+		{
+			psp->SetState(nullptr);
+			return 0;
+		}
+
 		psp->y += 9;
 		if (psp->y > WEAPONBOTTOM*2)
 		{
 			psp->SetState(nullptr);
 		}
+
 		if (self->player->extralight > 0) self->player->extralight--;
 	}
 	return 0;
 }
-
diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp
index 94a0084dd..2e285b34a 100644
--- a/src/p_pspr.cpp
+++ b/src/p_pspr.cpp
@@ -231,6 +231,9 @@ DPSprite *player_t::GetPSprite(PSPLayers layer)
 		}
 		if (layer == PSP_STRIFEHANDS)
 		{
+			// Some of the old hacks rely on this layer coming from the FireHands state.
+			// This is the ONLY time a psprite's state is actually null.
+			pspr->State = nullptr;
 			pspr->y = WEAPONTOP;
 		}
 

From 5c182c7fd795e9f525dbdf8409b1cc87bbf38f93 Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Fri, 8 Jul 2016 11:55:04 +0200
Subject: [PATCH 41/63] Fixed a crash with heretic's ChickenPlayer class

---
 src/d_player.h              | 5 ++++-
 src/g_heretic/a_chicken.cpp | 5 +++--
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/d_player.h b/src/d_player.h
index 48649de7a..e932223aa 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -532,7 +532,10 @@ public:
 	void TickPSprites();
 	void DestroyPSprites();
 	DPSprite *FindPSprite(int layer);
-	DPSprite *GetPSprite(PSPLayers layer); // Used ONLY for compatibility with the old hardcoded layers.
+	// Used ONLY for compatibility with the old hardcoded layers.
+	// Make sure that a state is properly set after calling this unless
+	// you are 100% sure the context already implies the layer exists.
+	DPSprite *GetPSprite(PSPLayers layer);
 };
 
 // Bookkeeping on players - state.
diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp
index b70e4ff08..7f62d5f0e 100644
--- a/src/g_heretic/a_chicken.cpp
+++ b/src/g_heretic/a_chicken.cpp
@@ -123,9 +123,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_Feathers)
 
 void P_UpdateBeak (AActor *self)
 {
-	if (self->player != nullptr)
+	DPSprite *pspr;
+	if (self->player != nullptr && (pspr = self->player->FindPSprite(PSP_WEAPON)) != nullptr)
 	{
-		self->player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + self->player->chickenPeck / 2;
+		pspr->y = WEAPONTOP + self->player->chickenPeck / 2;
 	}
 }
 

From 59593e57c6f04f5454481fe9756f491804738288 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Thu, 14 Jul 2016 09:27:29 -0500
Subject: [PATCH 42/63] - Fixed: RGF_ITEMS wasn't considered a part of the
 RGF_MASK flag.

---
 src/thingdef/thingdef_codeptr.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 4f4d88779..25d68fc8f 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -5669,7 +5669,9 @@ enum RadiusGiveFlags
 						RGF_MONSTERS |
 						RGF_OBJECTS |
 						RGF_VOODOO |
-						RGF_CORPSES | RGF_MISSILES,
+						RGF_CORPSES | 
+						RGF_MISSILES |
+						RGF_ITEMS,
 };
 
 static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amount, double distance, int flags, PClassActor *filter, FName species, double mindist)
@@ -5681,7 +5683,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo
 		if (!(flags & RGF_GIVESELF))
 			return false;
 	}
-	else if (thing->flags & MF_MISSILE)
+	if (thing->flags & MF_MISSILE)
 	{
 		if (!missilePass)
 			return false;

From 09175a6a7a9607e63f5513a01262777e35b8fe50 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Thu, 14 Jul 2016 09:55:13 -0500
Subject: [PATCH 43/63] This wasn't supposed to be committed...

---
 src/thingdef/thingdef_codeptr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 25d68fc8f..441ba4899 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -5683,7 +5683,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo
 		if (!(flags & RGF_GIVESELF))
 			return false;
 	}
-	if (thing->flags & MF_MISSILE)
+	else if (thing->flags & MF_MISSILE)
 	{
 		if (!missilePass)
 			return false;

From b121284fc023b6a211cfaa23d822d088cab40aaa Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Fri, 24 Jun 2016 13:19:49 -0500
Subject: [PATCH 44/63] Added GAF_SWITCH to GetAngle, inverting the function to
 get the caller's angle on the pointer instead.

---
 src/thingdef/thingdef_codeptr.cpp  | 13 ++++++++++---
 wadsrc/static/actors/actor.txt     |  2 +-
 wadsrc/static/actors/constants.txt |  6 ++++++
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 441ba4899..1b1c7b2cf 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -329,13 +329,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance)
 // NON-ACTION function to get the angle in degrees (normalized to -180..180)
 //
 //==========================================================================
+enum GAFlags
+{
+	GAF_RELATIVE =			1,
+	GAF_SWITCH =			1 << 1,
+};
+
 DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetAngle)
 {
 	if (numret > 0)
 	{
 		assert(ret != NULL);
 		PARAM_SELF_PROLOGUE(AActor);
-		PARAM_BOOL(relative);
+		PARAM_INT(flags);
 		PARAM_INT_OPT(ptr) { ptr = AAPTR_TARGET; }
 
 		AActor *target = COPY_AAPTR(self, ptr);
@@ -346,9 +352,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetAngle)
 		}
 		else
 		{
-			DVector3 diff = self->Vec3To(target);
+			DVector3 diff = (flags & GAF_SWITCH) ? target->Vec3To(self) : self->Vec3To(target);
 			DAngle angto = diff.Angle();
-			if (relative) angto = deltaangle(self->Angles.Yaw, angto);
+			DAngle yaw = (flags & GAF_SWITCH) ? target->Angles.Yaw : self->Angles.Yaw;
+			if (flags & GAF_RELATIVE) angto = deltaangle(yaw, angto);
 			ret->SetFloat(angto.Degrees);
 		}
 		return 1;
diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt
index 901d7a553..cb6ff4d93 100644
--- a/wadsrc/static/actors/actor.txt
+++ b/wadsrc/static/actors/actor.txt
@@ -41,7 +41,7 @@ ACTOR Actor native //: Thinker
 	native bool IsPointerEqual(int ptr_select1, int ptr_select2);
 	native int	CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
 	native float GetDistance(bool checkz, int ptr = AAPTR_DEFAULT);
-	native float GetAngle(bool relative, int ptr = AAPTR_DEFAULT);
+	native float GetAngle(int flags, int ptr = AAPTR_DEFAULT);
 	native float GetZAt(float px = 0, float py = 0, float angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT);
 	native int GetSpawnHealth();
 	native int GetGibHealth();
diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt
index 7b75b481d..46e810a7f 100644
--- a/wadsrc/static/actors/constants.txt
+++ b/wadsrc/static/actors/constants.txt
@@ -652,3 +652,9 @@ enum
 	BT_USER3		= 1<<23,
 	BT_USER4		= 1<<24,
 };
+// Flags for GetAngle
+enum
+{
+	GAF_RELATIVE =			1,
+	GAF_SWITCH =			1 << 1,
+};
\ No newline at end of file

From 74fc45d7b7f20f40e78ada6f3016366714edcab4 Mon Sep 17 00:00:00 2001
From: "alexey.lysiuk" <alexey.lysiuk@gmail.com>
Date: Sat, 16 Jul 2016 15:39:57 +0300
Subject: [PATCH 45/63] Fixed instant boss brain spawning

There was a possibility of division by zero which led to nonsensical spawn time
http://forum.zdoom.org/viewtopic.php?t=52760
---
 src/g_doom/a_bossbrain.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp
index 51ee77ff8..5d10e0138 100644
--- a/src/g_doom/a_bossbrain.cpp
+++ b/src/g_doom/a_bossbrain.cpp
@@ -147,7 +147,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
 			{
 				spit->special2 = 0;
 			}
-			else if (fabs(spit->Vel.X) > fabs(spit->Vel.Y))
+			else if (fabs(spit->Vel.Y) > fabs(spit->Vel.X))
 			{
 				spit->special2 = int((targ->Y() - self->Y()) / spit->Vel.Y);
 			}

From 58fb993402258d6f604b50d676444d9b37191dbe Mon Sep 17 00:00:00 2001
From: "alexey.lysiuk" <alexey.lysiuk@gmail.com>
Date: Sat, 16 Jul 2016 16:48:36 +0300
Subject: [PATCH 46/63] Added ability to select ammo image and text display
 order in alternative HUD

Controlled via hud_ammo_order CVAR:
* 0 (default): image and text
* any other value: text and image
---
 src/g_shared/shared_hud.cpp | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp
index 4bfe85271..46cf61d54 100644
--- a/src/g_shared/shared_hud.cpp
+++ b/src/g_shared/shared_hud.cpp
@@ -81,6 +81,7 @@ CVAR (Int ,  hud_showtime,		0,	    CVAR_ARCHIVE);	// Show time on HUD
 CVAR (Int ,  hud_timecolor,		CR_GOLD,CVAR_ARCHIVE);	// Color of in-game time on HUD
 CVAR (Int ,  hud_showlag,		0, CVAR_ARCHIVE);		// Show input latency (maketic - gametic difference)
 
+CVAR (Int, hud_ammo_order, 0, CVAR_ARCHIVE);				// ammo image and text order
 CVAR (Int, hud_ammo_red, 25, CVAR_ARCHIVE)					// ammo percent less than which status is red    
 CVAR (Int, hud_ammo_yellow, 50, CVAR_ARCHIVE)				// ammo percent less is yellow more green        
 CVAR (Int, hud_health_red, 25, CVAR_ARCHIVE)				// health amount less than which status is red   
@@ -586,9 +587,21 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
 	// ok, we got all ammo types. Now draw the list back to front (bottom to top)
 
 	int def_width = ConFont->StringWidth("000/000");
-	x-=def_width;
 	int yadd = ConFont->GetHeight();
 
+	int xtext = x - def_width;
+	int ximage = x;
+
+	if (hud_ammo_order > 0)
+	{
+		xtext -= 24;
+		ximage -= 20;
+	}
+	else
+	{
+		ximage -= def_width + 20;
+	}
+
 	for(i=orderedammos.Size()-1;i>=0;i--)
 	{
 
@@ -613,8 +626,8 @@ static int DrawAmmo(player_t *CPlayer, int x, int y)
 						 ammo < ( (maxammo * hud_ammo_red) / 100) ? CR_RED :   
 						 ammo < ( (maxammo * hud_ammo_yellow) / 100) ? CR_GOLD : CR_GREEN );
 
-		DrawHudText(ConFont, fontcolor, buf, x-tex_width, y+yadd, trans);
-		DrawImageToBox(TexMan[icon], x-20, y, 16, 8, trans);
+		DrawHudText(ConFont, fontcolor, buf, xtext-tex_width, y+yadd, trans);
+		DrawImageToBox(TexMan[icon], ximage, y, 16, 8, trans);
 		y-=10;
 	}
 	return y;

From da9f4cc1dd63201ddf29ec86610fd02be981f4c8 Mon Sep 17 00:00:00 2001
From: "alexey.lysiuk" <alexey.lysiuk@gmail.com>
Date: Sat, 16 Jul 2016 16:50:37 +0300
Subject: [PATCH 47/63] Added 'ammo display order' item to options menu

---
 wadsrc/static/language.enu | 3 +++
 wadsrc/static/menudef.txt  | 7 +++++++
 2 files changed, 10 insertions(+)

diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu
index d27374ed2..cef67aca9 100644
--- a/wadsrc/static/language.enu
+++ b/wadsrc/static/language.enu
@@ -1835,6 +1835,7 @@ ALTHUDMNU_SHOWAMMO				= "Show ammo for";
 ALTHUDMNU_SHOWTIME				= "Show time";
 ALTHUDMNU_TIMECOLOR				= "Time color";
 ALTHUDMNU_SHOWLAG				= "Show network latency";
+ALTHUDMNU_AMMOORDER				= "Ammo display order";
 ALTHUDMNU_AMMORED				= "Red ammo display below %";
 ALTHUDMNU_AMMOYELLOW			= "Yellow ammo display below %";
 ALTHUDMNU_HEALTHRED				= "Red health display below";
@@ -2210,6 +2211,8 @@ OPTVAL_SYSTEMSECONDS		= "System, seconds";
 OPTVAL_SYSTEM				= "System";
 OPTVAL_NETGAMESONLY			= "Netgames only";
 OPTVAL_ALWAYS				= "Always";
+OPTVAL_AMMOIMAGETEXT		= "Image and Text";
+OPTVAL_AMMOTEXTIMAGE		= "Text and Image";
 OPTVAL_SCRIPTSONLY			= "Scripts Only";
 OPTVAL_NEVER				= "Never";
 OPTVAL_ALL					= "All";
diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt
index bb854f378..2a59c4103 100644
--- a/wadsrc/static/menudef.txt
+++ b/wadsrc/static/menudef.txt
@@ -821,6 +821,12 @@ OptionValue "AltHUDLag"
 	2, "$OPTVAL_ALWAYS"
 }
 
+OptionValue "AltHUDAmmoOrder"
+{
+	0, "$OPTVAL_AMMOIMAGETEXT"
+	1, "$OPTVAL_AMMOTEXTIMAGE"
+}
+
 OptionMenu "AltHUDOptions"
 {
 	Title "$ALTHUDMNU_TITLE"
@@ -837,6 +843,7 @@ OptionMenu "AltHUDOptions"
 	Option "$ALTHUDMNU_SHOWTIME",				"hud_showtime", "AltHUDTime"
 	Option "$ALTHUDMNU_TIMECOLOR",				"hud_timecolor", "TextColors"
 	Option "$ALTHUDMNU_SHOWLAG",				"hud_showlag", "AltHUDLag"
+	Option "$ALTHUDMNU_AMMOORDER",				"hud_ammo_order", "AltHUDAmmoOrder"
 	Slider "$ALTHUDMNU_AMMORED",				"hud_ammo_red", 0, 100, 1, 0
 	Slider "$ALTHUDMNU_AMMOYELLOW",				"hud_ammo_yellow", 0, 100, 1, 0
 	Slider "$ALTHUDMNU_HEALTHRED",				"hud_health_red", 0, 100, 1, 0

From ee72760f3a01eecd23d87779e007d960bb4eb57b Mon Sep 17 00:00:00 2001
From: "alexey.lysiuk" <alexey.lysiuk@gmail.com>
Date: Sat, 16 Jul 2016 15:32:19 +0300
Subject: [PATCH 48/63] libc++ is now used by the linker too (when applicable)

---
 src/CMakeLists.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 67b7dbb17..5fe947ef8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -518,6 +518,7 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
 	# C++11 support using SDKs 10.7 and 10.8.
 	if ( APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
 		set( CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}" )
+		set( CMAKE_EXE_LINKER_FLAGS "-stdlib=libc++ ${CMAKE_EXE_LINKER_FLAGS}" )
 	endif ()
 
 	# Remove extra warnings when using the official DirectX headers.

From 3c7e1e0528d8716816980c9624d791168782a2c6 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Mon, 30 May 2016 15:16:05 -0500
Subject: [PATCH 49/63] - Added the tracer actor spawning for A_FireBullets and
 A_CustomBulletAttack.

The projectiles spawning conditions rely upon the puff successfully spawning.

# Conflicts:
#	wadsrc/static/actors/actor.txt
---
 src/thingdef/thingdef_codeptr.cpp         | 60 ++++++++++++++++++++---
 wadsrc/static/actors/actor.txt            |  2 +-
 wadsrc/static/actors/shared/inventory.txt |  2 +-
 3 files changed, 56 insertions(+), 8 deletions(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 1b1c7b2cf..61506a1c8 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1635,6 +1635,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 	PARAM_FLOAT_OPT	(range)			   { range = 0; }
 	PARAM_INT_OPT	(flags)			   { flags = 0; }
 	PARAM_INT_OPT	(ptr)			   { ptr = AAPTR_TARGET; }
+	PARAM_CLASS_OPT (missile, AActor)	{ missile = nullptr; }
+	PARAM_FLOAT_OPT (Spawnheight)		{ Spawnheight = 32; }
+	PARAM_FLOAT_OPT (Spawnofs_xy)		{ Spawnofs_xy = 0; }
 
 	AActor *ref = COPY_AAPTR(self, ptr);
 
@@ -1662,6 +1665,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 		{
 			DAngle angle = bangle;
 			DAngle slope = bslope;
+			DAngle tempangle = (pr_cwbullet.Random2() / 255.);
+			DAngle tempslope = (pr_cwbullet.Random2() / 255.);
 
 			if (flags & CBAF_EXPLICITANGLE)
 			{
@@ -1670,8 +1675,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 			}
 			else
 			{
-				angle += spread_xy * (pr_cwbullet.Random2() / 255.);
-				slope += spread_z * (pr_cwbullet.Random2() / 255.);
+				angle += spread_xy * tempangle;
+				slope += spread_z * tempslope;
 			}
 
 			int damage = damageperbullet;
@@ -1679,7 +1684,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 			if (!(flags & CBAF_NORANDOM))
 				damage *= ((pr_cabullet()%3)+1);
 
-			P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
+			AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
+
+			if (puff && missile)
+			{
+				double x = Spawnofs_xy * angle.Cos();
+				double y = Spawnofs_xy * angle.Sin();
+				AActor *proj = P_SpawnMissileXYZ(self->Vec3Offset(x, y, self->GetBobOffset() + Spawnheight), self, puff, missile, false);
+				if (proj)
+				{
+					double missilespeed;
+					A_Face(proj, puff, 0., 0.);
+					missilespeed = fabs(proj->Angles.Pitch.Cos() * proj->Speed);
+					proj->Vel.Z = proj->Angles.Pitch.Sin() * proj->Speed;
+					proj->VelFromAngle(missilespeed);
+				}
+			}
 		}
     }
 	return 0;
@@ -1810,6 +1830,28 @@ enum FB_Flags
 	FBF_NORANDOMPUFFZ = 32,
 };
 
+static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff, DAngle angle, double Spawnheight, double Spawnofs_xy)
+{
+	if (self && missile && puff)
+	{
+		double x = Spawnofs_xy * angle.Cos();
+		double y = Spawnofs_xy * angle.Sin();
+		DAngle ang = self->Angles.Yaw - 90;
+		DVector2 ofs = ang.ToVector(Spawnofs_xy);
+		//AActor *proj = P_SpawnMissileXYZ(self->Vec3Offset(x, y, z + self->GetBobOffset()), self, puff, missile, false);
+
+		AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, angle, nullptr, nullptr, false, true);
+		if (proj)
+		{
+			double missilespeed;
+			A_Face(proj, puff, 0., 0.);
+			missilespeed = fabs(proj->Angles.Pitch.Cos() * proj->Speed);
+			proj->Vel.Z = proj->Angles.Pitch.Sin() * proj->Speed;
+			proj->VelFromAngle(missilespeed);
+		}
+	}
+}
+
 DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 {
 	PARAM_ACTION_PROLOGUE;
@@ -1817,9 +1859,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 	PARAM_ANGLE		(spread_z);
 	PARAM_INT		(numbullets);
 	PARAM_INT		(damageperbullet);
-	PARAM_CLASS_OPT	(pufftype, AActor)	{ pufftype = NULL; }
+	PARAM_CLASS_OPT	(pufftype, AActor)	{ pufftype = nullptr; }
 	PARAM_INT_OPT	(flags)				{ flags = FBF_USEAMMO; }
 	PARAM_FLOAT_OPT	(range)				{ range = 0; }
+	PARAM_CLASS_OPT (missile, AActor)	{ missile = nullptr; }
+	PARAM_FLOAT_OPT (Spawnheight)		{ Spawnheight = 0; }
+	PARAM_FLOAT_OPT (Spawnofs_xy)		{ Spawnofs_xy = 0; }
 
 	if (!self->player) return 0;
 
@@ -1858,7 +1903,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 		if (!(flags & FBF_NORANDOM))
 			damage *= ((pr_cwbullet()%3)+1);
 
-		P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags);
+		AActor *puff = P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags);
+		FireBulletMissile(self, missile, puff, bangle, Spawnheight, Spawnofs_xy);
+
 	}
 	else 
 	{
@@ -1885,7 +1932,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 			if (!(flags & FBF_NORANDOM))
 				damage *= ((pr_cwbullet()%3)+1);
 
-			P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
+			AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
+			FireBulletMissile(self, missile, puff, angle, Spawnheight, Spawnofs_xy);
 		}
 	}
 	return 0;
diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt
index cb6ff4d93..8c35df21b 100644
--- a/wadsrc/static/actors/actor.txt
+++ b/wadsrc/static/actors/actor.txt
@@ -189,7 +189,7 @@ ACTOR Actor native //: Thinker
 	native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10);
 	native state A_Jump(int chance = 256, state label, ...);
 	native void A_CustomMissile(class<Actor> missiletype, float spawnheight = 32, float spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET);
-	native void A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET);
+	native void A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET, class<Actor> missile = "", float Spawnheight = 32, float Spawnofs_xy = 0);
 	native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270, int limit = 0);
 	native state A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT);
 	native state A_JumpIfCloser(float distance, state label, bool noz = false);
diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt
index a49dfd14c..43a33f93a 100644
--- a/wadsrc/static/actors/shared/inventory.txt
+++ b/wadsrc/static/actors/shared/inventory.txt
@@ -9,7 +9,7 @@ ACTOR Inventory native
 	
 	action native state A_JumpIfNoAmmo(state label);
 	action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class<Actor> pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class<BasicArmorBonus> armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = "");
-	action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", int flags = 1, float range = 0);
+	action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", int flags = 1, float range = 0, class<Actor> missile = "", float Spawnheight = 32, float Spawnofs_xy = 0);
 	action native A_FireCustomMissile(class<Actor> missiletype, float angle = 0, bool useammo = true, float spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0);
 	action native A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270, int limit = 0);
 	action native A_Light(int extralight);

From 791852a6bdfb14119cbefc7968ddd3cddd7317e9 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Mon, 30 May 2016 15:29:23 -0500
Subject: [PATCH 50/63] Cleaned up.

---
 src/thingdef/thingdef_codeptr.cpp | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 61506a1c8..784bb3518 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1665,8 +1665,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 		{
 			DAngle angle = bangle;
 			DAngle slope = bslope;
-			DAngle tempangle = (pr_cwbullet.Random2() / 255.);
-			DAngle tempslope = (pr_cwbullet.Random2() / 255.);
 
 			if (flags & CBAF_EXPLICITANGLE)
 			{
@@ -1675,8 +1673,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 			}
 			else
 			{
-				angle += spread_xy * tempangle;
-				slope += spread_z * tempslope;
+				angle += spread_xy * (pr_cwbullet.Random2() / 255.);
+				slope += spread_z * (pr_cwbullet.Random2() / 255.);
 			}
 
 			int damage = damageperbullet;
@@ -1838,7 +1836,6 @@ static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff,
 		double y = Spawnofs_xy * angle.Sin();
 		DAngle ang = self->Angles.Yaw - 90;
 		DVector2 ofs = ang.ToVector(Spawnofs_xy);
-		//AActor *proj = P_SpawnMissileXYZ(self->Vec3Offset(x, y, z + self->GetBobOffset()), self, puff, missile, false);
 
 		AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, angle, nullptr, nullptr, false, true);
 		if (proj)

From cc8e7f8de6a34d1ee671d2d989504df6d42ab20c Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Mon, 30 May 2016 15:31:19 -0500
Subject: [PATCH 51/63] Cleaning finished.

---
 src/thingdef/thingdef_codeptr.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 784bb3518..ce1f4f4c5 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1832,8 +1832,6 @@ static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff,
 {
 	if (self && missile && puff)
 	{
-		double x = Spawnofs_xy * angle.Cos();
-		double y = Spawnofs_xy * angle.Sin();
 		DAngle ang = self->Angles.Yaw - 90;
 		DVector2 ofs = ang.ToVector(Spawnofs_xy);
 

From 4750dfd8b6c261901d561521ba6733fada886298 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Mon, 30 May 2016 18:08:43 -0500
Subject: [PATCH 52/63] Added ability to set the puffs directly as the spawned
 projectile's target, master, and/or tracer.

---
 src/thingdef/thingdef_codeptr.cpp | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index ce1f4f4c5..f3118c3dd 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1622,6 +1622,9 @@ enum CBA_Flags
 	CBAF_EXPLICITANGLE = 4,
 	CBAF_NOPITCH = 8,
 	CBAF_NORANDOMPUFFZ = 16,
+	CBAF_PUFFTARGET = 32,
+	CBAF_PUFFMASTER = 64,
+	CBAF_PUFFTRACER = 128,
 };
 
 DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
@@ -1691,6 +1694,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 				AActor *proj = P_SpawnMissileXYZ(self->Vec3Offset(x, y, self->GetBobOffset() + Spawnheight), self, puff, missile, false);
 				if (proj)
 				{
+					if (flags & CBAF_PUFFTARGET)	proj->target = puff;
+					if (flags & CBAF_PUFFMASTER)	proj->master = puff;
+					if (flags & CBAF_PUFFTRACER)	proj->tracer = puff;
 					double missilespeed;
 					A_Face(proj, puff, 0., 0.);
 					missilespeed = fabs(proj->Angles.Pitch.Cos() * proj->Speed);
@@ -1826,9 +1832,12 @@ enum FB_Flags
 	FBF_NOPITCH = 8,
 	FBF_NOFLASH = 16,
 	FBF_NORANDOMPUFFZ = 32,
+	FBF_PUFFTARGET = 64,
+	FBF_PUFFMASTER = 128,
+	FBF_PUFFTRACER = 256,
 };
 
-static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff, DAngle angle, double Spawnheight, double Spawnofs_xy)
+static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff, DAngle angle, double Spawnheight, double Spawnofs_xy, int flags)
 {
 	if (self && missile && puff)
 	{
@@ -1838,6 +1847,9 @@ static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff,
 		AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, angle, nullptr, nullptr, false, true);
 		if (proj)
 		{
+			if (flags & FBF_PUFFTARGET)	proj->target = puff;
+			if (flags & FBF_PUFFMASTER)	proj->master = puff;
+			if (flags & FBF_PUFFTRACER)	proj->tracer = puff;
 			double missilespeed;
 			A_Face(proj, puff, 0., 0.);
 			missilespeed = fabs(proj->Angles.Pitch.Cos() * proj->Speed);
@@ -1899,7 +1911,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 			damage *= ((pr_cwbullet()%3)+1);
 
 		AActor *puff = P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags);
-		FireBulletMissile(self, missile, puff, bangle, Spawnheight, Spawnofs_xy);
+		FireBulletMissile(self, missile, puff, bangle, Spawnheight, Spawnofs_xy, flags);
 
 	}
 	else 
@@ -1928,7 +1940,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 				damage *= ((pr_cwbullet()%3)+1);
 
 			AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
-			FireBulletMissile(self, missile, puff, angle, Spawnheight, Spawnofs_xy);
+			FireBulletMissile(self, missile, puff, angle, Spawnheight, Spawnofs_xy, flags);
 		}
 	}
 	return 0;

From 10fabc3ab7feb06c3435ad8bd0837ef9171331e1 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Sun, 19 Jun 2016 10:59:00 -0500
Subject: [PATCH 53/63] Cleaned up code. Puffs no longer need ALWAYSPUFF.

- A_CustomBulletAttack and A_FireBullets will perform a second P_LineAttack to get a puff which only returns to the previous function after a tracer.
---
 src/p_local.h                     |  3 +-
 src/p_map.cpp                     | 51 ++++++++++++++--------
 src/thingdef/thingdef_codeptr.cpp | 70 ++++++++++++++++++++++---------
 3 files changed, 87 insertions(+), 37 deletions(-)

diff --git a/src/p_local.h b/src/p_local.h
index ac6b264d9..42b4da7e7 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -325,7 +325,8 @@ enum	// P_LineAttack flags
 {
 	LAF_ISMELEEATTACK = 1,
 	LAF_NORANDOMPUFFZ = 2,
-	LAF_NOIMPACTDECAL = 4
+	LAF_NOIMPACTDECAL = 4,
+	LAF_NOINTERACT =	8,
 };
 
 AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL);
diff --git a/src/p_map.cpp b/src/p_map.cpp
index 2fe41b17b..d63bf18b6 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -4096,6 +4096,7 @@ static ETraceStatus CheckForActor(FTraceResults &res, void *userdata)
 AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
 	DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage)
 {
+	bool nointeract = !!(flags && LAF_NOINTERACT);
 	DVector3 direction;
 	double shootz;
 	FTraceResults trace;
@@ -4185,26 +4186,32 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
 	}
 
 	int tflags;
-	if (puffDefaults != NULL && puffDefaults->flags6 & MF6_NOTRIGGER) tflags = TRACE_NoSky;
+	if (nointeract || (puffDefaults && puffDefaults->flags6 & MF6_NOTRIGGER)) tflags = TRACE_NoSky;
 	else tflags = TRACE_NoSky | TRACE_Impact;
 
 	if (!Trace(t1->PosAtZ(shootz), t1->Sector, direction, distance, MF_SHOOTABLE, 
 		ML_BLOCKEVERYTHING | ML_BLOCKHITSCAN, t1, trace, tflags, CheckForActor, &TData))
 	{ // hit nothing
-		if (puffDefaults == NULL)
-		{
-		}
-		else if (puffDefaults->ActiveSound)
+		if (!nointeract && puffDefaults && puffDefaults->ActiveSound)
 		{ // Play miss sound
 			S_Sound(t1, CHAN_WEAPON, puffDefaults->ActiveSound, 1, ATTN_NORM);
 		}
-		if (puffDefaults != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF)
+
+		// [MC] LAF_NOINTERACT guarantees puff spawning and returns it directly to the calling function.
+		// No damage caused, no sounds played, no blood splatters.
+
+		if (nointeract || (puffDefaults && puffDefaults->flags3 & MF3_ALWAYSPUFF))
 		{ // Spawn the puff anyway
 			puff = P_SpawnPuff(t1, pufftype, trace.HitPos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget, 2, puffFlags);
+
+			if (nointeract)
+			{
+				return puff;
+			}
 		}
 		else
 		{
-			return NULL;
+			return nullptr;
 		}
 	}
 	else
@@ -4212,12 +4219,17 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
 		if (trace.HitType != TRACE_HitActor)
 		{
 			// position a bit closer for puffs
-			if (trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky))
+			if (nointeract || trace.HitType != TRACE_HitWall || ((trace.Line->special != Line_Horizon) || spawnSky))
 			{
 				DVector2 pos = P_GetOffsetPosition(trace.HitPos.X, trace.HitPos.Y, -trace.HitVector.X * 4, -trace.HitVector.Y * 4);
 				puff = P_SpawnPuff(t1, pufftype, DVector3(pos, trace.HitPos.Z - trace.HitVector.Z * 4), trace.SrcAngleFromTarget,
 					trace.SrcAngleFromTarget - 90, 0, puffFlags);
 				puff->radius = 1/65536.;
+
+				if (nointeract)
+				{
+					return puff;
+				}
 			}
 
 			// [RH] Spawn a decal
@@ -4255,14 +4267,6 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
 		}
 		else
 		{
-			bool bloodsplatter = (t1->flags5 & MF5_BLOODSPLATTER) ||
-				(t1->player != NULL &&	t1->player->ReadyWeapon != NULL &&
-				(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
-
-			bool axeBlood = (t1->player != NULL &&
-				t1->player->ReadyWeapon != NULL &&
-				(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
-
 			// Hit a thing, so it could be either a puff or blood
 			DVector3 bleedpos = trace.HitPos;
 			// position a bit closer for puffs/blood if using compatibility mode.
@@ -4275,7 +4279,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
 			}
 
 			// Spawn bullet puffs or blood spots, depending on target type.
-			if ((puffDefaults != NULL && puffDefaults->flags3 & MF3_PUFFONACTORS) ||
+			if (nointeract || (puffDefaults && puffDefaults->flags3 & MF3_PUFFONACTORS) ||
 				(trace.Actor->flags & MF_NOBLOOD) ||
 				(trace.Actor->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)))
 			{
@@ -4284,6 +4288,11 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
 
 				// We must pass the unreplaced puff type here 
 				puff = P_SpawnPuff(t1, pufftype, bleedpos, trace.SrcAngleFromTarget, trace.SrcAngleFromTarget - 90, 2, puffFlags | PF_HITTHING, trace.Actor);
+
+				if (nointeract)
+				{
+					return puff;
+				}
 			}
 
 			// Allow puffs to inflict poison damage, so that hitscans can poison, too.
@@ -4320,6 +4329,14 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
 			}
 			if (!(puffDefaults != NULL && puffDefaults->flags3&MF3_BLOODLESSIMPACT))
 			{
+				bool bloodsplatter = (t1->flags5 & MF5_BLOODSPLATTER) ||
+					(t1->player != nullptr &&	t1->player->ReadyWeapon != nullptr &&
+						(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
+
+				bool axeBlood = (t1->player != nullptr &&
+					t1->player->ReadyWeapon != nullptr &&
+					(t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD));
+
 				if (!bloodsplatter && !axeBlood &&
 					!(trace.Actor->flags & MF_NOBLOOD) &&
 					!(trace.Actor->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)))
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index f3118c3dd..10d0d4498 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1666,6 +1666,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 		S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
 		for (i = 0; i < numbullets; i++)
 		{
+			bool temp = false;
 			DAngle angle = bangle;
 			DAngle slope = bslope;
 
@@ -1686,6 +1687,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 				damage *= ((pr_cabullet()%3)+1);
 
 			AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
+			if (!puff)
+			{
+				temp = true;
+				puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+			}
 
 			if (puff && missile)
 			{
@@ -1694,14 +1700,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 				AActor *proj = P_SpawnMissileXYZ(self->Vec3Offset(x, y, self->GetBobOffset() + Spawnheight), self, puff, missile, false);
 				if (proj)
 				{
-					if (flags & CBAF_PUFFTARGET)	proj->target = puff;
-					if (flags & CBAF_PUFFMASTER)	proj->master = puff;
-					if (flags & CBAF_PUFFTRACER)	proj->tracer = puff;
-					double missilespeed;
-					A_Face(proj, puff, 0., 0.);
-					missilespeed = fabs(proj->Angles.Pitch.Cos() * proj->Speed);
-					proj->Vel.Z = proj->Angles.Pitch.Sin() * proj->Speed;
-					proj->VelFromAngle(missilespeed);
+					// FAF_BOTTOM = 1
+					// Aim for the base of the puff as that's where blood puffs will spawn... roughly.
+
+					A_Face(proj, puff, 0., 0., 0., 0., 1);
+					proj->Vel3DFromAngle(-proj->Angles.Pitch, proj->Speed);
+
+					if (temp)
+						puff->Destroy();
+					else
+					{
+						if (flags & CBAF_PUFFTARGET)	proj->target = puff;
+						if (flags & CBAF_PUFFMASTER)	proj->master = puff;
+						if (flags & CBAF_PUFFTRACER)	proj->tracer = puff;
+					}
 				}
 			}
 		}
@@ -1837,7 +1849,7 @@ enum FB_Flags
 	FBF_PUFFTRACER = 256,
 };
 
-static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff, DAngle angle, double Spawnheight, double Spawnofs_xy, int flags)
+static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff, DAngle angle, double Spawnheight, double Spawnofs_xy, int flags, bool temp)
 {
 	if (self && missile && puff)
 	{
@@ -1847,14 +1859,20 @@ static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff,
 		AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, angle, nullptr, nullptr, false, true);
 		if (proj)
 		{
-			if (flags & FBF_PUFFTARGET)	proj->target = puff;
-			if (flags & FBF_PUFFMASTER)	proj->master = puff;
-			if (flags & FBF_PUFFTRACER)	proj->tracer = puff;
-			double missilespeed;
-			A_Face(proj, puff, 0., 0.);
-			missilespeed = fabs(proj->Angles.Pitch.Cos() * proj->Speed);
-			proj->Vel.Z = proj->Angles.Pitch.Sin() * proj->Speed;
-			proj->VelFromAngle(missilespeed);
+			// FAF_BOTTOM = 1
+			// Aim for the base of the puff as that's where blood puffs will spawn... roughly.
+
+			A_Face(proj, puff, 0., 0., 0., 0., 1);
+			proj->Vel3DFromAngle(-proj->Angles.Pitch, proj->Speed);
+
+			if (temp)
+				puff->Destroy();
+			else
+			{
+				if (flags & FBF_PUFFTARGET)	proj->target = puff;
+				if (flags & FBF_PUFFMASTER)	proj->master = puff;
+				if (flags & FBF_PUFFTRACER)	proj->tracer = puff;
+			}
 		}
 	}
 }
@@ -1910,8 +1928,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 		if (!(flags & FBF_NORANDOM))
 			damage *= ((pr_cwbullet()%3)+1);
 
+		bool temp = false;
 		AActor *puff = P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags);
-		FireBulletMissile(self, missile, puff, bangle, Spawnheight, Spawnofs_xy, flags);
+
+		if (!puff)
+		{
+			temp = true;
+			puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+		}
+		FireBulletMissile(self, missile, puff, bangle, Spawnheight, Spawnofs_xy, flags, temp);
 
 	}
 	else 
@@ -1939,8 +1964,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 			if (!(flags & FBF_NORANDOM))
 				damage *= ((pr_cwbullet()%3)+1);
 
+			bool temp = false;
 			AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
-			FireBulletMissile(self, missile, puff, angle, Spawnheight, Spawnofs_xy, flags);
+
+			if (!puff)
+			{
+				temp = true;
+				puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+			}
+			FireBulletMissile(self, missile, puff, angle, Spawnheight, Spawnofs_xy, flags, temp);
 		}
 	}
 	return 0;

From 02064437c5481bfe9766acfd87aa670b82870310 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Wed, 22 Jun 2016 19:34:14 -0500
Subject: [PATCH 54/63] Fixed wrong angle/slopes being used and one too many &s
 for NOINTERACT.

---
 src/p_map.cpp                     | 2 +-
 src/thingdef/thingdef_codeptr.cpp | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/p_map.cpp b/src/p_map.cpp
index d63bf18b6..1684ee534 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -4096,7 +4096,7 @@ static ETraceStatus CheckForActor(FTraceResults &res, void *userdata)
 AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
 	DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage)
 {
-	bool nointeract = !!(flags && LAF_NOINTERACT);
+	bool nointeract = !!(flags & LAF_NOINTERACT);
 	DVector3 direction;
 	double shootz;
 	FTraceResults trace;
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 10d0d4498..7f9a6edfe 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1690,7 +1690,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 			if (!puff)
 			{
 				temp = true;
-				puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+				puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
 			}
 
 			if (puff && missile)
@@ -1970,7 +1970,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 			if (!puff)
 			{
 				temp = true;
-				puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+				puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
 			}
 			FireBulletMissile(self, missile, puff, angle, Spawnheight, Spawnofs_xy, flags, temp);
 		}

From 376c9b030650c460dcc5df1ab5576df0759a9485 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Wed, 13 Jul 2016 09:48:24 -0500
Subject: [PATCH 55/63] - Optimized handling of puffs in the event they're
 null. - Only spawn the puff as needed again if the projectile actually
 spawns.

---
 src/thingdef/thingdef_codeptr.cpp | 103 ++++++++++++++++++------------
 1 file changed, 62 insertions(+), 41 deletions(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 7f9a6edfe..734ef2ef7 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1666,7 +1666,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 		S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
 		for (i = 0; i < numbullets; i++)
 		{
-			bool temp = false;
 			DAngle angle = bangle;
 			DAngle slope = bslope;
 
@@ -1687,32 +1686,39 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 				damage *= ((pr_cabullet()%3)+1);
 
 			AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
-			if (!puff)
-			{
-				temp = true;
-				puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
-			}
-
-			if (puff && missile)
+			if (missile != nullptr && pufftype != nullptr)
 			{
 				double x = Spawnofs_xy * angle.Cos();
 				double y = Spawnofs_xy * angle.Sin();
-				AActor *proj = P_SpawnMissileXYZ(self->Vec3Offset(x, y, self->GetBobOffset() + Spawnheight), self, puff, missile, false);
+				
+				DVector3 pos = self->Pos();
+				self->SetXYZ(self->Vec3Offset(x, y, 0.));
+				AActor *proj = P_SpawnMissileAngleZSpeed(self, self->Z() + self->GetBobOffset() + Spawnheight, missile, self->Angles.Yaw, 0, GetDefaultByType(missile)->Speed, self, false);
+				self->SetXYZ(pos);
+				
 				if (proj)
 				{
-					// FAF_BOTTOM = 1
-					// Aim for the base of the puff as that's where blood puffs will spawn... roughly.
-
-					A_Face(proj, puff, 0., 0., 0., 0., 1);
-					proj->Vel3DFromAngle(-proj->Angles.Pitch, proj->Speed);
-
-					if (temp)
-						puff->Destroy();
-					else
+					bool temp = (puff == nullptr);
+					if (!puff)
 					{
-						if (flags & CBAF_PUFFTARGET)	proj->target = puff;
-						if (flags & CBAF_PUFFMASTER)	proj->master = puff;
-						if (flags & CBAF_PUFFTRACER)	proj->tracer = puff;
+						puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+					}
+					if (puff)
+					{			
+						// FAF_BOTTOM = 1
+						// Aim for the base of the puff as that's where blood puffs will spawn... roughly.
+
+						A_Face(proj, puff, 0., 0., 0., 0., 1);
+						proj->Vel3DFromAngle(-proj->Angles.Pitch, proj->Speed);
+
+						if (temp)
+							puff->Destroy();
+						else
+						{
+							if (flags & CBAF_PUFFTARGET)	proj->target = puff;
+							if (flags & CBAF_PUFFMASTER)	proj->master = puff;
+							if (flags & CBAF_PUFFTRACER)	proj->tracer = puff;
+						}
 					}
 				}
 			}
@@ -1849,14 +1855,10 @@ enum FB_Flags
 	FBF_PUFFTRACER = 256,
 };
 
-static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff, DAngle angle, double Spawnheight, double Spawnofs_xy, int flags, bool temp)
+static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp)
 {
-	if (self && missile && puff)
+	if (proj && puff)
 	{
-		DAngle ang = self->Angles.Yaw - 90;
-		DVector2 ofs = ang.ToVector(Spawnofs_xy);
-
-		AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, angle, nullptr, nullptr, false, true);
 		if (proj)
 		{
 			// FAF_BOTTOM = 1
@@ -1865,9 +1867,7 @@ static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff,
 			A_Face(proj, puff, 0., 0., 0., 0., 1);
 			proj->Vel3DFromAngle(-proj->Angles.Pitch, proj->Speed);
 
-			if (temp)
-				puff->Destroy();
-			else
+			if (!temp)
 			{
 				if (flags & FBF_PUFFTARGET)	proj->target = puff;
 				if (flags & FBF_PUFFMASTER)	proj->master = puff;
@@ -1875,6 +1875,10 @@ static void FireBulletMissile(AActor *self, PClassActor *missile, AActor *puff,
 			}
 		}
 	}
+	if (puff && temp)
+	{
+		puff->Destroy();
+	}
 }
 
 DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
@@ -1928,16 +1932,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 		if (!(flags & FBF_NORANDOM))
 			damage *= ((pr_cwbullet()%3)+1);
 
-		bool temp = false;
 		AActor *puff = P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags);
 
-		if (!puff)
+		if (missile != nullptr)
 		{
-			temp = true;
-			puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+			bool temp = false;
+			DAngle ang = self->Angles.Yaw - 90;
+			DVector2 ofs = ang.ToVector(Spawnofs_xy);
+			AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, bangle, nullptr, nullptr, false, true);
+			if (proj)
+			{
+				if (!puff)
+				{
+					temp = true;
+					puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+				}
+				AimBulletMissile(proj, puff, flags, temp);
+			}
 		}
-		FireBulletMissile(self, missile, puff, bangle, Spawnheight, Spawnofs_xy, flags, temp);
-
 	}
 	else 
 	{
@@ -1964,15 +1976,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 			if (!(flags & FBF_NORANDOM))
 				damage *= ((pr_cwbullet()%3)+1);
 
-			bool temp = false;
 			AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags);
 
-			if (!puff)
+			if (missile != nullptr)
 			{
-				temp = true;
-				puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+				bool temp = false;
+				DAngle ang = self->Angles.Yaw - 90;
+				DVector2 ofs = ang.ToVector(Spawnofs_xy);
+				AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, angle, nullptr, nullptr, false, true);
+				if (proj)
+				{
+					if (!puff)
+					{
+						temp = true;
+						puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
+					}
+					AimBulletMissile(proj, puff, flags, temp);
+				}
 			}
-			FireBulletMissile(self, missile, puff, angle, Spawnheight, Spawnofs_xy, flags, temp);
 		}
 	}
 	return 0;

From 7544adfc912e899400b2a250be33cd8247cfc534 Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Wed, 13 Jul 2016 10:15:10 -0500
Subject: [PATCH 56/63] Combined the target/master/tracer checking into
 AimBulletMissile.

---
 src/thingdef/thingdef_codeptr.cpp | 38 +++++++++++++++----------------
 1 file changed, 18 insertions(+), 20 deletions(-)

diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index 734ef2ef7..63ba6ec30 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1627,6 +1627,8 @@ enum CBA_Flags
 	CBAF_PUFFTRACER = 128,
 };
 
+static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, bool cba);
+
 DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 {
 	PARAM_SELF_PROLOGUE(AActor);
@@ -1705,20 +1707,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack)
 					}
 					if (puff)
 					{			
-						// FAF_BOTTOM = 1
-						// Aim for the base of the puff as that's where blood puffs will spawn... roughly.
-
-						A_Face(proj, puff, 0., 0., 0., 0., 1);
-						proj->Vel3DFromAngle(-proj->Angles.Pitch, proj->Speed);
-
-						if (temp)
-							puff->Destroy();
-						else
-						{
-							if (flags & CBAF_PUFFTARGET)	proj->target = puff;
-							if (flags & CBAF_PUFFMASTER)	proj->master = puff;
-							if (flags & CBAF_PUFFTRACER)	proj->tracer = puff;
-						}
+						AimBulletMissile(proj, puff, flags, temp, true);
 					}
 				}
 			}
@@ -1855,7 +1844,7 @@ enum FB_Flags
 	FBF_PUFFTRACER = 256,
 };
 
-static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp)
+static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, bool cba)
 {
 	if (proj && puff)
 	{
@@ -1869,9 +1858,18 @@ static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp)
 
 			if (!temp)
 			{
-				if (flags & FBF_PUFFTARGET)	proj->target = puff;
-				if (flags & FBF_PUFFMASTER)	proj->master = puff;
-				if (flags & FBF_PUFFTRACER)	proj->tracer = puff;
+				if (cba)
+				{
+					if (flags & CBAF_PUFFTARGET)	proj->target = puff;
+					if (flags & CBAF_PUFFMASTER)	proj->master = puff;
+					if (flags & CBAF_PUFFTRACER)	proj->tracer = puff;
+				}
+				else
+				{
+					if (flags & FBF_PUFFTARGET)	proj->target = puff;
+					if (flags & FBF_PUFFMASTER)	proj->master = puff;
+					if (flags & FBF_PUFFTRACER)	proj->tracer = puff;
+				}
 			}
 		}
 	}
@@ -1947,7 +1945,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 					temp = true;
 					puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
 				}
-				AimBulletMissile(proj, puff, flags, temp);
+				AimBulletMissile(proj, puff, flags, temp, false);
 			}
 		}
 	}
@@ -1991,7 +1989,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
 						temp = true;
 						puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT);
 					}
-					AimBulletMissile(proj, puff, flags, temp);
+					AimBulletMissile(proj, puff, flags, temp, false);
 				}
 			}
 		}

From c150116f79aa04479f0cec0e697c546567af7a54 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Sat, 16 Jul 2016 19:55:00 +0200
Subject: [PATCH 57/63] - fixed: When changing weapons due to starting or
 ending a Tome of Power effect, the PSprite's caller needs to be changed.

In this case the PSprite animation won't be changed, only the ReadyWeapon. But in order to work, the PSprite's caller needs to change as well so that the next weapon check does not fail.
---
 src/g_shared/a_artifacts.cpp | 17 ++++++++++++++++-
 src/g_shared/a_weapons.cpp   | 13 ++++++++++++-
 src/p_pspr.h                 |  1 +
 3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp
index 07071daa6..b5ac970ca 100644
--- a/src/g_shared/a_artifacts.cpp
+++ b/src/g_shared/a_artifacts.cpp
@@ -1127,12 +1127,27 @@ void APowerWeaponLevel2::InitEffect ()
 
 	assert (sister->SisterWeapon == weapon);
 
-	Owner->player->ReadyWeapon = sister;
 
 	if (weapon->GetReadyState() != sister->GetReadyState())
 	{
+		Owner->player->ReadyWeapon = sister;
 		P_SetPsprite(Owner->player, PSP_WEAPON, sister->GetReadyState());
 	}
+	else
+	{
+		DPSprite *psp = Owner->player->FindPSprite(PSP_WEAPON);
+		if (psp != nullptr && psp->GetCaller() == Owner->player->ReadyWeapon)
+		{
+			// If the weapon changes but the state does not, we have to manually change the PSprite's caller here.
+			psp->SetCaller(sister);
+			Owner->player->ReadyWeapon = sister;
+		}
+		else
+		{
+			// Something went wrong. Initiate a regular weapon change.
+			Owner->player->PendingWeapon = sister;
+		}
+	}
 }
 
 //===========================================================================
diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp
index e7ebfc77b..575914fe8 100644
--- a/src/g_shared/a_weapons.cpp
+++ b/src/g_shared/a_weapons.cpp
@@ -642,7 +642,18 @@ void AWeapon::EndPowerup ()
 		}
 		else
 		{
-			Owner->player->ReadyWeapon = SisterWeapon;
+			DPSprite *psp = Owner->player->FindPSprite(PSP_WEAPON);
+			if (psp != nullptr && psp->GetCaller() == Owner->player->ReadyWeapon)
+			{
+				// If the weapon changes but the state does not, we have to manually change the PSprite's caller here.
+				psp->SetCaller(SisterWeapon);
+				Owner->player->ReadyWeapon = SisterWeapon;
+			}
+			else
+			{
+				// Something went wrong. Initiate a regular weapon change.
+				Owner->player->PendingWeapon = SisterWeapon;
+			}
 		}
 	}
 }
diff --git a/src/p_pspr.h b/src/p_pspr.h
index a7cf49f8c..41d258df8 100644
--- a/src/p_pspr.h
+++ b/src/p_pspr.h
@@ -76,6 +76,7 @@ public:
 	FState*		GetState()	const { return State; }
 	DPSprite*	GetNext()	      { return Next; }
 	AActor*		GetCaller()	      { return Caller; }
+	void		SetCaller(AActor *newcaller) { Caller = newcaller; }
 
 	double x, y;
 	double oldx, oldy;

From 35c30ab62fee6cdd3e746aeeacebcfbfeadbe60c Mon Sep 17 00:00:00 2001
From: MajorCooke <paul.growney22@gmail.com>
Date: Sat, 16 Jul 2016 20:28:43 -0500
Subject: [PATCH 58/63] Fixed missing constants.

---
 wadsrc/static/actors/constants.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt
index 46e810a7f..05049e598 100644
--- a/wadsrc/static/actors/constants.txt
+++ b/wadsrc/static/actors/constants.txt
@@ -38,6 +38,9 @@ const int CBAF_NORANDOM = 2;
 const int CBAF_EXPLICITANGLE = 4;
 const int CBAF_NOPITCH = 8;
 const int CBAF_NORANDOMPUFFZ = 16;
+const int CBAF_PUFFTARGET = 32;
+const int CBAF_PUFFMASTER = 64;
+const int CBAF_PUFFTRACER = 128;
 
 // Flags for A_GunFlash
 const int GFF_NOEXTCHANGE = 1;
@@ -210,6 +213,9 @@ const int CPF_STEALARMOR = 32;
 const int FPF_AIMATANGLE = 1;
 const int FPF_TRANSFERTRANSLATION = 2;
 const int FPF_NOAUTOAIM = 4;
+const int FBF_PUFFTARGET = 64;
+const int FBF_PUFFMASTER = 128;
+const int FBF_PUFFTRACER = 256;
 
 // Flags for A_Teleport
 enum

From 39042dc4bf11226d3cfe8a28a64703f622d97c6e Mon Sep 17 00:00:00 2001
From: "alexey.lysiuk" <alexey.lysiuk@gmail.com>
Date: Sun, 17 Jul 2016 08:15:23 +0300
Subject: [PATCH 59/63] macOS application controller is now using proper
 delegate protocol

Fixes compilation error with Xcode 8:
cannot initialize a parameter of type 'id<NSApplicationDelegate> _Nullable' with an lvalue of type 'ApplicationController *'
---
 src/posix/cocoa/i_main.mm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm
index 5729a3716..bbe344809 100644
--- a/src/posix/cocoa/i_main.mm
+++ b/src/posix/cocoa/i_main.mm
@@ -220,8 +220,8 @@ int OriginalMain(int argc, char** argv)
 
 
 @interface ApplicationController : NSResponder
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-	<NSFileManagerDelegate>
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+	<NSApplicationDelegate>
 #endif
 {
 }

From e482a543891b755b7a2b2a7546e7187983daef62 Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Sat, 16 Jul 2016 16:07:31 +0200
Subject: [PATCH 60/63] Fixed a crash with A_ClearOverlays

---
 src/p_pspr.cpp | 33 +++++++++++----------------------
 1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp
index 2e285b34a..4d5ab660b 100644
--- a/src/p_pspr.cpp
+++ b/src/p_pspr.cpp
@@ -1171,50 +1171,39 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ClearOverlays)
 	PARAM_INT_OPT(stop) { stop = 0; }
 	PARAM_BOOL_OPT(safety) { safety = true; }
 
-	if (!self->player)
+	if (self->player == nullptr)
 		ACTION_RETURN_INT(0);
 
-	player_t *player = self->player;
 	if (!start && !stop)
 	{
 		start = INT_MIN;
 		stop = safety ? PSP_TARGETCENTER - 1 : INT_MAX;
 	}
 
-	int count = 0;
-	DPSprite *pspr = player->psprites;
-	int startID = (pspr != nullptr) ? pspr->GetID() : start;
-	bool first = true;
-	while (pspr != nullptr)
-	{
-		if (pspr->GetID() == startID)
-		{
-			if (first)
-				first = false;
-			else
-				break;
-		}
-		int id = pspr->GetID();
+	unsigned int count = 0;
+	int id;
 
-		//Do not wipe out layer 0. Ever.
-		if (!id || id < start)
+	for (DPSprite *pspr = self->player->psprites; pspr != nullptr; pspr = pspr->GetNext())
+	{
+		id = pspr->GetID();
+
+		if (id < start || id == 0)
 			continue;
-		if (id > stop)
+		else if (id > stop)
 			break;
 
 		if (safety)
 		{
 			if (id >= PSP_TARGETCENTER)
 				break;
-			else if ((id >= PSP_STRIFEHANDS && id <= PSP_WEAPON) || (id == PSP_FLASH))
+			else if (id == PSP_STRIFEHANDS || id == PSP_WEAPON || id == PSP_FLASH)
 				continue;
 		}
 
-		// [MC]Don't affect non-hardcoded layers unless it's really desired.
 		pspr->SetState(nullptr);
 		count++;
-		pspr = pspr->GetNext();
 	}
+
 	ACTION_RETURN_INT(count);
 }
 

From 446bc1018c86a4a0e08244a148c775cf986e148e Mon Sep 17 00:00:00 2001
From: Leonard2 <hobbax3@gmail.com>
Date: Sat, 16 Jul 2016 15:22:36 +0200
Subject: [PATCH 61/63] Fixed: weapons didn't clear their flash layer when the
 player died

---
 src/p_pspr.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp
index 4d5ab660b..bad9c2d73 100644
--- a/src/p_pspr.cpp
+++ b/src/p_pspr.cpp
@@ -1085,9 +1085,8 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower)
 	}
 	if (player->playerstate == PST_DEAD)
 	{ // Player is dead, so don't bring up a pending weapon
-		psp->y = WEAPONBOTTOM;
-	
 		// Player is dead, so keep the weapon off screen
+		P_SetPsprite(player, PSP_FLASH, nullptr);
 		psp->SetState(nullptr);
 		return 0;
 	}

From 8369833dc5f5cc85781c76fb7ce70ff45cb89d80 Mon Sep 17 00:00:00 2001
From: "alexey.lysiuk" <alexey.lysiuk@gmail.com>
Date: Sun, 17 Jul 2016 15:34:57 +0300
Subject: [PATCH 62/63] Fixed setting of custom color for static text in menu

---
 src/menu/menudef.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp
index 6d5e3dd64..1948153e4 100644
--- a/src/menu/menudef.cpp
+++ b/src/menu/menudef.cpp
@@ -662,7 +662,7 @@ static EColorRange ParseOptionColor(FScanner &sc, FOptionMenuDescriptor *desc)
 	if (sc.CheckString(","))
 	{
 		sc.MustGetString();
-		EColorRange cr = V_FindFontColor(sc.String);
+		cr = V_FindFontColor(sc.String);
 		if (cr == CR_UNTRANSLATED && !sc.Compare("untranslated") && isdigit(sc.String[0]))
 		{
 			if (strtol(sc.String, NULL, 0)) cr = OptionSettings.mFontColorHeader;

From d4352dd1a75d3a21927961d05d4a9c771ba4cfa1 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Sun, 17 Jul 2016 23:13:10 +0200
Subject: [PATCH 63/63] - fixed slope calculation error.

---
 src/r_plane.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/r_plane.cpp b/src/r_plane.cpp
index d749319e3..ff23492ab 100644
--- a/src/r_plane.cpp
+++ b/src/r_plane.cpp
@@ -1677,7 +1677,7 @@ void R_DrawTiltedPlane (visplane_t *pl, double _xscale, double _yscale, fixed_t
 	// the textures a constant size across the surface's plane instead.
 	cosine = cos(planeang), sine = sin(planeang);
 	m[1] = pl->height.ZatPoint(ViewPos.X + yscale * sine, ViewPos.Y + yscale * cosine) - zeroheight;
-	n[1] = pl->height.ZatPoint(ViewPos.X - xscale * cosine, ViewPos.Y + xscale * sine) - zeroheight;
+	n[1] = -(pl->height.ZatPoint(ViewPos.X - xscale * cosine, ViewPos.Y + xscale * sine) - zeroheight);
 
 	plane_su = p ^ m;
 	plane_sv = p ^ n;