From d13499d2b7d4726cf7c391c4345105a1d9391482 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Sun, 11 Aug 2019 09:00:29 +0200
Subject: [PATCH] - fixed the extremely long standing bug that Lost Souls
 didn't reacquire their target when slamming into something.

This was one of that annoying old design mistakes where Doom and Heretic features were poorly merged together. The Heretic Gargoyle uses very similar coding but performs a subtly different action when actually hitting another actor. This different action was made the default, even for the Lost Soul.
It has now been changed that both monsters use their original action, being distinguished by an actor flag. For compatibility with custom definitions Heretic's behavior, which has been the default in ZDoom will be the preferred one. The one of the Lost Soul can be reactivated by a flag.
---
 src/actor.h                                   |  1 +
 src/d_dehacked.cpp                            | 23 +++++++++----------
 src/p_mobj.cpp                                |  2 +-
 src/scripting/thingdef_data.cpp               |  1 +
 wadsrc/static/zscript/actors/doom/lostsoul.zs |  2 +-
 5 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/src/actor.h b/src/actor.h
index 1c18bdc67..f8d18a204 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -408,6 +408,7 @@ enum ActorFlag8
 	MF8_HITOWNER		= 0x00000010,	// projectile can hit the actor that fired it
 	MF8_NOFRICTION		= 0x00000020,	// friction doesn't apply to the actor at all
 	MF8_NOFRICTIONBOUNCE	= 0x00000040,	// don't bounce off walls when on icy floors
+	MF8_RETARGETAFTERSLAM	= 0x00000080	// Forces jumping to the idle state after slamming into something
 };
 
 // --- mobj.renderflags ---
diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp
index ed767dc95..90f9f0867 100644
--- a/src/d_dehacked.cpp
+++ b/src/d_dehacked.cpp
@@ -362,14 +362,8 @@ inline double DEHToDouble(int acsval)
 
 static void PushTouchedActor(PClassActor *cls)
 {
-	for(unsigned i = 0; i < TouchedActors.Size(); i++)
-	{
-		if (TouchedActors[i] == cls)
-		{
-			return;
-		}
-	}
-	TouchedActors.Push(cls);
+	if (TouchedActors.Find(cls) == TouchedActors.Size())
+		TouchedActors.Push(cls);
 }
 
 
@@ -3011,6 +3005,13 @@ void FinishDehPatch ()
 	unsigned int touchedIndex;
 	unsigned int nameindex = 0;
 
+	// For compatibility all potentially altered actors now using A_SkullFly need to be set to the original slamming behavior.
+	// Since this flag does not affect anything else let's just set it for everything, it will just be ignored by non-charging things.
+	for (auto cls : InfoNames)
+	{
+		GetDefaultByType(cls)->flags8 |= MF8_RETARGETAFTERSLAM;
+	}
+
 	for (touchedIndex = 0; touchedIndex < TouchedActors.Size(); ++touchedIndex)
 	{
 		PClassActor *subclass;
@@ -3076,10 +3077,8 @@ void FinishDehPatch ()
 		}
 	}
 	// Now that all Dehacked patches have been processed, it's okay to free StateMap.
-	StateMap.Clear();
-	StateMap.ShrinkToFit();
-	TouchedActors.Clear();
-	TouchedActors.ShrinkToFit();
+	StateMap.Reset();
+	TouchedActors.Reset();
 	EnglishStrings.Clear();
 	GStrings.SetDehackedStrings(std::move(DehStrings));
 
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 4838dbfb9..c6b67fc4d 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -3155,7 +3155,7 @@ bool AActor::Slam (AActor *thing)
 			// The charging monster may have died by the target's actions here.
 			if (health > 0)
 			{
-				if (SeeState != NULL) SetState (SeeState);
+				if (SeeState != NULL && !(flags8 & MF8_RETARGETAFTERSLAM)) SetState (SeeState);
 				else SetIdle();
 			}
 		}
diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp
index 4352a8e42..71b21e010 100644
--- a/src/scripting/thingdef_data.cpp
+++ b/src/scripting/thingdef_data.cpp
@@ -329,6 +329,7 @@ static FFlagDef ActorFlagDefs[]=
 	DEFINE_FLAG(MF8, HITOWNER, AActor, flags8),
 	DEFINE_FLAG(MF8, NOFRICTION, AActor, flags8),
 	DEFINE_FLAG(MF8, NOFRICTIONBOUNCE, AActor, flags8),
+	DEFINE_FLAG(MF8, RETARGETAFTERSLAM, AActor, flags8),
 
 	// Effect flags
 	DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
diff --git a/wadsrc/static/zscript/actors/doom/lostsoul.zs b/wadsrc/static/zscript/actors/doom/lostsoul.zs
index 89086bf17..055781079 100644
--- a/wadsrc/static/zscript/actors/doom/lostsoul.zs
+++ b/wadsrc/static/zscript/actors/doom/lostsoul.zs
@@ -15,7 +15,7 @@ class LostSoul : Actor
 		Damage 3;
 		PainChance 256;
 		Monster;
-		+FLOAT +NOGRAVITY +MISSILEMORE +DONTFALL +NOICEDEATH +ZDOOMTRANS;
+		+FLOAT +NOGRAVITY +MISSILEMORE +DONTFALL +NOICEDEATH +ZDOOMTRANS +RETARGETAFTERSLAM
 		AttackSound "skull/melee";
 		PainSound "skull/pain";
 		DeathSound "skull/death";