From 652606f70b89c62cb419fe1f151564a1e0e5df54 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Sat, 24 Nov 2018 19:29:52 +0100
Subject: [PATCH] - scriptified A_Explode and relatives.

---
 src/p_actionfunctions.cpp               | 113 ---------------
 src/p_enemy.cpp                         |  14 --
 src/p_local.h                           |   2 +-
 src/p_map.cpp                           |  14 +-
 src/p_mobj.cpp                          |  23 ----
 wadsrc/static/zscript/actor.txt         |  68 +--------
 wadsrc/static/zscript/actor_attacks.txt | 175 +++++++++++++++++++++++-
 wadsrc/static/zscript/constants.txt     |  10 ++
 8 files changed, 200 insertions(+), 219 deletions(-)

diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp
index 50ff36e23b..ff375974c3 100644
--- a/src/p_actionfunctions.cpp
+++ b/src/p_actionfunctions.cpp
@@ -1186,119 +1186,6 @@ DEFINE_ACTION_FUNCTION(AActor, CheckInventory)
 }
 
 
-//==========================================================================
-//
-// Parameterized version of A_Explode
-//
-//==========================================================================
-
-enum
-{
-	XF_HURTSOURCE =		1,
-	XF_NOTMISSILE =		4,
-	XF_NOACTORTYPE =	1 << 3,
-	XF_NOSPLASH	=		16,
-};
-
-DEFINE_ACTION_FUNCTION(AActor, A_Explode)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-	PARAM_INT	(damage);
-	PARAM_INT	(distance);
-	PARAM_INT	(flags);
-	PARAM_BOOL	(alert);
-	PARAM_INT	(fulldmgdistance);
-	PARAM_INT	(nails);
-	PARAM_INT	(naildamage);
-	PARAM_CLASS	(pufftype, AActor);
-	PARAM_NAME	(damagetype);
-
-	if (damage < 0)	// get parameters from metadata
-	{
-		damage = self->IntVar(NAME_ExplosionDamage);
-		distance = self->IntVar(NAME_ExplosionRadius);
-		flags = !self->BoolVar(NAME_DontHurtShooter);
-		alert = false;
-	}
-	if (distance <= 0) distance = damage;
-
-	// NailBomb effect, from SMMU but not from its source code: instead it was implemented and
-	// generalized from the documentation at http://www.doomworld.com/eternity/engine/codeptrs.html
-
-	if (nails)
-	{
-		DAngle ang;
-		for (int i = 0; i < nails; i++)
-		{
-			ang = i*360./nails;
-			// Comparing the results of a test wad with Eternity, it seems A_NailBomb does not aim
-			P_LineAttack(self, ang, MISSILERANGE, 0.,
-				//P_AimLineAttack (self, ang, MISSILERANGE), 
-				naildamage, NAME_Hitscan, pufftype, (self->flags & MF_MISSILE) ? LAF_TARGETISSOURCE : 0);
-		}
-	}
-
-	if (!(flags & XF_NOACTORTYPE) && damagetype == NAME_None)
-	{
-		damagetype = self->DamageType;
-	}
-
-	int pflags = 0;
-	if (flags & XF_HURTSOURCE)	pflags |= RADF_HURTSOURCE;
-	if (flags & XF_NOTMISSILE)	pflags |= RADF_SOURCEISSPOT;
-
-	int count = P_RadiusAttack (self, self->target, damage, distance, damagetype, pflags, fulldmgdistance);
-	if (!(flags & XF_NOSPLASH)) P_CheckSplash(self, distance);
-	if (alert && self->target != NULL && self->target->player != NULL)
-	{
-		P_NoiseAlert(self->target, self);
-	}
-	ACTION_RETURN_INT(count);
-}
-
-//==========================================================================
-//
-// A_RadiusThrust
-//
-//==========================================================================
-
-enum
-{
-	RTF_AFFECTSOURCE =			1,
-	RTF_NOIMPACTDAMAGE =		2,
-	RTF_NOTMISSILE =			4,
-};
-
-DEFINE_ACTION_FUNCTION(AActor, A_RadiusThrust)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-	PARAM_INT	(force);
-	PARAM_INT	(distance);
-	PARAM_INT	(flags);
-	PARAM_INT	(fullthrustdistance);
-
-	bool sourcenothrust = false;
-
-	if (force == 0) force = 128;
-	if (distance <= 0) distance = abs(force);
-
-	// Temporarily negate MF2_NODMGTHRUST on the shooter, since it renders this function useless.
-	if (!(flags & RTF_NOTMISSILE) && self->target != NULL && self->target->flags2 & MF2_NODMGTHRUST)
-	{
-		sourcenothrust = true;
-		self->target->flags2 &= ~MF2_NODMGTHRUST;
-	}
-
-	P_RadiusAttack (self, self->target, force, distance, self->DamageType, flags | RADF_NODAMAGE, fullthrustdistance);
-	P_CheckSplash(self, distance);
-
-	if (sourcenothrust)
-	{
-		self->target->flags2 |= MF2_NODMGTHRUST;
-	}
-	return 0;
-}
-
 //==========================================================================
 //
 // A_RadiusDamageSelf
diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp
index 4e7499e1b4..72e9b6e092 100644
--- a/src/p_enemy.cpp
+++ b/src/p_enemy.cpp
@@ -3409,20 +3409,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_Pain)
 	return 0;
 }
 
-//
-// A_Detonate
-// killough 8/9/98: same as A_Explode, except that the damage is variable
-//
-
-DEFINE_ACTION_FUNCTION(AActor, A_Detonate)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-	int damage = self->GetMissileDamage(0, 1);
-	P_RadiusAttack (self, self->target, damage, damage, self->DamageType, RADF_HURTSOURCE);
-	P_CheckSplash(self, damage);
-	return 0;
-}
-
 bool CheckBossDeath (AActor *actor)
 {
 	int i;
diff --git a/src/p_local.h b/src/p_local.h
index 66a1b304e2..26d6f8b644 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -359,7 +359,6 @@ void	P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff);		// hitsc
 void	P_TraceBleed (int damage, AActor *target);		// random direction version
 bool	P_HitFloor (AActor *thing);
 bool	P_HitWater (AActor *thing, sector_t *sec, const DVector3 &pos, bool checkabove = false, bool alert = true, bool force = false);
-void	P_CheckSplash(AActor *self, double distance);
 
 struct FRailParams
 {
@@ -410,6 +409,7 @@ enum
 	RADF_SOURCEISSPOT = 4,
 	RADF_NODAMAGE = 8,
 	RADF_THRUSTZ = 16,
+	RADF_OLDRADIUSDAMAGE = 32
 };
 int	P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, 
 						FName damageType, int flags, int fulldamagedistance=0);
diff --git a/src/p_map.cpp b/src/p_map.cpp
index 33916fdb23..fc29afb061 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -6229,7 +6229,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom
 		// them far too "active." BossBrains also use the old code
 		// because some user levels require they have a height of 16,
 		// which can make them near impossible to hit with the new code.
-		if ((flags & RADF_NODAMAGE) || !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG))
+		if (((flags & RADF_NODAMAGE) || !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG)) && !(flags & RADF_OLDRADIUSDAMAGE))
 		{
 			double points = P_GetRadiusDamage(false, bombspot, thing, bombdamage, bombdistance, fulldamagedistance, bombsource == thing);
 			double check = int(points) * bombdamage;
@@ -6306,6 +6306,18 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom
 	return count;
 }
 
+DEFINE_ACTION_FUNCTION(AActor, RadiusAttack)
+{
+	PARAM_SELF_PROLOGUE(AActor);
+	PARAM_OBJECT(bombsource, AActor);
+	PARAM_INT(bombdamage);
+	PARAM_INT(bombdistance);
+	PARAM_NAME(damagetype);
+	PARAM_INT(flags);
+	PARAM_INT(fulldamagedistance);
+	ACTION_RETURN_INT(P_RadiusAttack(self, bombsource, bombdamage, bombdistance, damagetype, flags, fulldamagedistance));
+}
+
 //==========================================================================
 //
 // SECTOR HEIGHT CHANGING
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 9d3b7d931c..6ee0e61267 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -6777,29 +6777,6 @@ DEFINE_ACTION_FUNCTION(AActor, HitFloor)
 	ACTION_RETURN_BOOL(P_HitFloor(self));
 }
 
-//---------------------------------------------------------------------------
-//
-// P_CheckSplash
-//
-// Checks for splashes caused by explosions
-//
-//---------------------------------------------------------------------------
-
-void P_CheckSplash(AActor *self, double distance)
-{
-	sector_t *floorsec;
-	self->Sector->LowestFloorAt(self, &floorsec);
-	if (self->Z() <= self->floorz + distance && self->floorsector == floorsec && self->Sector->GetHeightSec() == NULL && floorsec->heightsec == NULL)
-	{
-		// Explosion splashes never alert monsters. This is because A_Explode has
-		// a separate parameter for that so this would get in the way of proper 
-		// behavior.
-		DVector3 pos = self->PosRelative(floorsec);
-		pos.Z = self->floorz;
-		P_HitWater (self, floorsec, pos, false, false);
-	}
-}
-
 //---------------------------------------------------------------------------
 //
 // FUNC P_CheckMissileSpawn
diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt
index 1021977e9e..49762d994a 100644
--- a/wadsrc/static/zscript/actor.txt
+++ b/wadsrc/static/zscript/actor.txt
@@ -964,69 +964,6 @@ class Actor : Thinker native
 	native bool A_LineEffect(int boomspecial = 0, int tag = 0);
 	// End of MBF redundant functions.
 	
-
-	//==========================================================================
-	//
-	// old customizable attack functions which use actor parameters.
-	//
-	//==========================================================================
-	
-	private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class<Actor> MissileType,double MissileHeight)
-	{
-		let targ = target;
-		if (targ == NULL) return;
-
-		A_FaceTarget ();
-		if (domelee && MeleeDamage>0 && CheckMeleeRange ())
-		{
-			int damage = random[CustomMelee](1, 8) * MeleeDamage;
-			if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON);
-			int newdam = targ.DamageMobj (self, self, damage, 'Melee');
-			targ.TraceBleed (newdam > 0 ? newdam : damage, self);
-		}
-		else if (domissile && MissileType != NULL)
-		{
-			// This seemingly senseless code is needed for proper aiming.
-			double add = MissileHeight + GetBobOffset() - 32;
-			AddZ(add);
-			Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), targ, MissileType, false);
-			AddZ(-add);
-
-			if (missile)
-			{
-				// automatic handling of seeker missiles
-				if (missile.bSeekerMissile)
-				{
-					missile.tracer = targ;
-				}
-				missile.CheckMissileSpawn(radius);
-			}
-		}
-	}
-
-	deprecated("2.3") void A_MeleeAttack()
-	{
-		DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
-	}
-
-	deprecated("2.3") void A_MissileAttack()
-	{
-		Class<Actor> MissileType = MissileName;
-		DoAttack(false, true, 0, 0, MissileType, MissileHeight);
-	}
-
-	deprecated("2.3") void A_ComboAttack()
-	{
-		Class<Actor> MissileType = MissileName;
-		DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
-	}
-
-	void A_BasicAttack(int melee_damage, sound melee_sound, class<actor> missile_type, double missile_height)
-	{
-		DoAttack(true, true, melee_damage, melee_sound, missile_type, missile_height);
-	}
-
-
 	native void A_MonsterRail();
 	native void A_Pain();
 	native void A_NoBlocking(bool drop = true);
@@ -1038,7 +975,6 @@ class Actor : Thinker native
 	native void A_VileChase();
 	native bool A_CheckForResurrection();
 	native void A_BossDeath();
-	native void A_Detonate();
 	bool A_CallSpecial(int special, int arg1=0, int arg2=0, int arg3=0, int arg4=0, int arg5=0)
 	{
 		return Level.ExecuteSpecial(special, self, null, false, arg1, arg2, arg3, arg4, arg5);
@@ -1110,10 +1046,10 @@ class Actor : Thinker native
 	native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true);
 	native void A_CustomComboAttack(class<Actor> missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true);
 	native void A_Burst(class<Actor> chunktype);
-	native void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0);
 	native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class<Actor> flashtype = null);
-	native int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class<Actor> pufftype = "BulletPuff", name damagetype = "none");
 	native int GetRadiusDamage(Actor thing, int damage, int distance, int fulldmgdistance = 0, bool oldradiusdmg = false);
+	native int RadiusAttack(Actor bombsource, int bombdamage, int bombdistance, Name bombmod = 'none', int flags = RADF_HURTSOURCE, int fulldamagedistance = 0);
+	
 	native void A_Stop();
 	native void A_Respawn(int flags = 1);
 	native void A_RestoreSpecialPosition();
diff --git a/wadsrc/static/zscript/actor_attacks.txt b/wadsrc/static/zscript/actor_attacks.txt
index 44c32d1f98..22a2a4386b 100644
--- a/wadsrc/static/zscript/actor_attacks.txt
+++ b/wadsrc/static/zscript/actor_attacks.txt
@@ -529,7 +529,180 @@ extend class Actor
 		}
 	}
 
+	//---------------------------------------------------------------------------
+	//
+	// P_CheckSplash
+	//
+	// Checks for splashes caused by explosions
+	//
+	//---------------------------------------------------------------------------
+
+	void CheckSplash(double distance)
+	{
+		double floorh;
+		sector floorsec;
+		[floorh, floorsec] = curSector.LowestFloorAt(pos.XY);
+
+		if (pos.Z <= floorz + distance && floorsector == floorsec && curSector.GetHeightSec() == NULL && floorsec.heightsec == NULL)
+		{
+			// Explosion splashes never alert monsters. This is because A_Explode has
+			// a separate parameter for that so this would get in the way of proper 
+			// behavior.
+			Vector3 pos = PosRelative(floorsec);
+			pos.Z = floorz;
+			HitWater (floorsec, pos, false, false);
+		}
+	}
+
+	//==========================================================================
+	//
+	// Parameterized version of A_Explode
+	//
+	//==========================================================================
+
+	int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldmgdistance = 0, int nails = 0, int naildamage = 10, class<Actor> pufftype = "BulletPuff", name damagetype = "none")
+	{
+
+		if (damage < 0)	// get parameters from metadata
+		{
+			damage = ExplosionDamage;
+			distance = ExplosionRadius;
+			flags = !DontHurtShooter;
+			alert = false;
+		}
+		if (distance <= 0) distance = damage;
+
+		// NailBomb effect, from SMMU but not from its source code: instead it was implemented and
+		// generalized from the documentation at http://www.doomworld.com/eternity/engine/codeptrs.html
+
+		if (nails)
+		{
+			double ang;
+			for (int i = 0; i < nails; i++)
+			{
+				ang = i*360./nails;
+				// Comparing the results of a test wad with Eternity, it seems A_NailBomb does not aim
+				LineAttack(ang, MISSILERANGE, 0.,
+					//P_AimLineAttack (self, ang, MISSILERANGE), 
+					naildamage, 'Hitscan', pufftype, bMissile ? LAF_TARGETISSOURCE : 0);
+			}
+		}
+
+		if (!(flags & XF_EXPLICITDAMAGETYPE) && damagetype == 'None')
+		{
+			damagetype = self.DamageType;
+		}
+
+		int pflags = 0;
+		if (flags & XF_HURTSOURCE)	pflags |= RADF_HURTSOURCE;
+		if (flags & XF_NOTMISSILE)	pflags |= RADF_SOURCEISSPOT;
+
+		int count = RadiusAttack (target, damage, distance, damagetype, pflags, fulldmgdistance);
+		if (!(flags & XF_NOSPLASH)) CheckSplash(distance);
+		if (alert && target != NULL && target.player != NULL)
+		{
+			SoundAlert(target);
+		}
+		return count;
+	}
+
+	//==========================================================================
+	//
+	// A_RadiusThrust
+	//
+	//==========================================================================
+
+	void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0)
+	{
+		if (force == 0) force = 128;
+		if (distance <= 0) distance = abs(force);
+
+		bool nothrust = target.bNoDamageThrust;
+		// Temporarily negate MF2_NODMGTHRUST on the shooter, since it renders this function useless.
+		if (!(flags & RTF_NOTMISSILE) && target != NULL)
+		{
+			target.bNoDamageThrust = false;
+		}
+
+		RadiusAttack (target, force, distance, DamageType, flags | RADF_NODAMAGE, fullthrustdistance);
+		CheckSplash(distance);
+		target.bNoDamageThrust = nothrust;
+	}
+
+	//==========================================================================
+	//
+	// A_Detonate
+	// killough 8/9/98: same as A_Explode, except that the damage is variable
+	//
+	//==========================================================================
+
+	void A_Detonate()
+	{
+		int damage = GetMissileDamage(0, 1);
+		RadiusAttack (target, damage, damage, DamageType, RADF_HURTSOURCE);
+		CheckSplash(damage);
+	}
+
+	//==========================================================================
+	//
+	// old customizable attack functions which use actor parameters.
+	//
+	//==========================================================================
+	
+	private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class<Actor> MissileType,double MissileHeight)
+	{
+		let targ = target;
+		if (targ == NULL) return;
+
+		A_FaceTarget ();
+		if (domelee && MeleeDamage>0 && CheckMeleeRange ())
+		{
+			int damage = random[CustomMelee](1, 8) * MeleeDamage;
+			if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON);
+			int newdam = targ.DamageMobj (self, self, damage, 'Melee');
+			targ.TraceBleed (newdam > 0 ? newdam : damage, self);
+		}
+		else if (domissile && MissileType != NULL)
+		{
+			// This seemingly senseless code is needed for proper aiming.
+			double add = MissileHeight + GetBobOffset() - 32;
+			AddZ(add);
+			Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), targ, MissileType, false);
+			AddZ(-add);
+
+			if (missile)
+			{
+				// automatic handling of seeker missiles
+				if (missile.bSeekerMissile)
+				{
+					missile.tracer = targ;
+				}
+				missile.CheckMissileSpawn(radius);
+			}
+		}
+	}
+
+	deprecated("2.3") void A_MeleeAttack()
+	{
+		DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
+	}
+
+	deprecated("2.3") void A_MissileAttack()
+	{
+		Class<Actor> MissileType = MissileName;
+		DoAttack(false, true, 0, 0, MissileType, MissileHeight);
+	}
+
+	deprecated("2.3") void A_ComboAttack()
+	{
+		Class<Actor> MissileType = MissileName;
+		DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
+	}
+
+	void A_BasicAttack(int melee_damage, sound melee_sound, class<actor> missile_type, double missile_height)
+	{
+		DoAttack(true, true, melee_damage, melee_sound, missile_type, missile_height);
+	}
 
 	
-	
 }
diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt
index ccb3f48488..fe2c8a901e 100644
--- a/wadsrc/static/zscript/constants.txt
+++ b/wadsrc/static/zscript/constants.txt
@@ -1247,3 +1247,13 @@ enum SPAC
 
 	SPAC_PlayerActivate = (SPAC_Cross|SPAC_Use|SPAC_Impact|SPAC_Push|SPAC_AnyCross|SPAC_UseThrough|SPAC_UseBack),
 };
+
+enum RadiusDamageFlags
+{
+	RADF_HURTSOURCE = 1,
+	RADF_NOIMPACTDAMAGE = 2,
+	RADF_SOURCEISSPOT = 4,
+	RADF_NODAMAGE = 8,
+	RADF_THRUSTZ = 16,
+	RADF_OLDRADIUSDAMAGE = 32
+};