From 542083af30adab73e4685e1b02a1a7b02566d06a Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Thu, 29 Dec 2022 16:59:07 +0100
Subject: [PATCH] - merged both hitradius variants, now that all the critical
 differences are properly handled by actor flags.

---
 source/games/duke/src/actors.cpp    | 128 +++++++++++++++++++++++++++-
 source/games/duke/src/actors_d.cpp  | 114 -------------------------
 source/games/duke/src/actors_r.cpp  |  96 ---------------------
 source/games/duke/src/dispatch.cpp  |   4 -
 source/games/duke/src/duke3d.h      |   1 -
 source/games/duke/src/funct.h       |   2 +-
 source/games/duke/src/gameexec.cpp  |   2 +-
 source/games/duke/src/vmexports.cpp |   9 +-
 8 files changed, 131 insertions(+), 225 deletions(-)

diff --git a/source/games/duke/src/actors.cpp b/source/games/duke/src/actors.cpp
index 73389dcd8..b80213e9f 100644
--- a/source/games/duke/src/actors.cpp
+++ b/source/games/duke/src/actors.cpp
@@ -763,7 +763,7 @@ void detonate(DDukeActor *actor, PClassActor* explosion)
 	{
 		int x = actor->spr.extra;
 		spawn(actor, explosion);
-		fi.hitradius(actor, gs.seenineblastradius, x >> 2, x - (x >> 1), x - (x >> 2), x);
+		hitradius(actor, gs.seenineblastradius, x >> 2, x - (x >> 1), x - (x >> 2), x);
 		S_PlayActorSound(PIPEBOMB_EXPLODE, actor);
 	}
 
@@ -852,6 +852,132 @@ void blastceiling(DDukeActor* actor, double radius)
 		}
 	}
 }
+
+//---------------------------------------------------------------------------
+//
+// 
+//
+//---------------------------------------------------------------------------
+
+void hitradius(DDukeActor* actor, int  r, int  hp1, int  hp2, int  hp3, int  hp4)
+{
+	double radius = r * inttoworld;
+	static const uint8_t statlist[] = { STAT_DEFAULT, STAT_ACTOR, STAT_STANDABLE, STAT_PLAYER, STAT_FALLER, STAT_ZOMBIEACTOR, STAT_MISC };
+
+	if (!(actor->flags3 & SFLAG3_NOCEILINGBLAST))
+	{
+		blastceiling(actor, radius);
+	}
+
+	double q = zrand(32) - (isRR() ? 24 : 16);
+
+	auto Owner = actor->GetOwner();
+	for (int x = 0; x < 7; x++)
+	{
+		DukeStatIterator itj(statlist[x]);
+		while (auto act2 = itj.Next())
+		{
+			if (Owner)
+			{
+				if (Owner->isPlayer() && act2->isPlayer() && ud.coop != 0 && ud.ffire == 0 && Owner != act2 /* && (dmflags & NOFRIENDLYRADIUSDMG)*/)
+				{
+					continue;
+				}
+
+				if (actor->flags3 & SFLAG3_HITRADIUS_DONTHURTSPECIES && !Owner->isPlayer() && Owner->GetClass() == act2->GetClass())
+				{
+					continue;
+				}
+			}
+
+			if (x == 0 || x >= 5 || (act2->flags1 & SFLAG_HITRADIUS_CHECKHITONLY))
+			{
+				if (!(actor->flags3 & SFLAG3_HITRADIUS_NODAMAGE) || (act2->spr.cstat & CSTAT_SPRITE_BLOCK_ALL))
+					if ((actor->spr.pos - act2->spr.pos).Length() < radius)
+					{
+						if (badguy(act2) && !cansee(act2->spr.pos.plusZ(q), act2->sector(), actor->spr.pos.plusZ(q), actor->sector()))
+							continue;
+						checkhitsprite(act2, actor);
+					}
+			}
+			else if (act2->spr.extra >= 0 && act2 != actor && ((act2->flags1 & SFLAG_HITRADIUS_FORCEEFFECT) || badguy(act2) || (act2->spr.cstat & CSTAT_SPRITE_BLOCK_ALL)))
+			{
+				// this is a damage type check, not a projectile type check.
+				// It's also quite broken because it doesn't check for being shrunk but tries to guess it from the size.
+				// Unfortunately, with CON there is no way to retrieve proper shrunk state in any way.
+				if (actor->GetClass() == DukeShrinkSparkClass && (act2->spr.scale.X < 0.375)) 
+				{
+					continue;
+				}
+				if (actor->flags3 & SFLAG3_HITRADIUS_DONTHURTSHOOTER && act2 == Owner)
+				{
+					continue;
+				}
+				if (actor->flags3 & SFLAG3_HITRADIUS_NOEFFECT)
+				{
+					continue;
+				}
+
+				double dist = (act2->getPosWithOffsetZ() - actor->spr.pos).Length();
+
+				if (dist < radius && cansee(act2->spr.pos.plusZ(-8), act2->sector(), actor->spr.pos.plusZ(-12), actor->sector()))
+				{
+					act2->hitang = (act2->spr.pos - actor->spr.pos).Angle();
+					act2->attackertype = CallGetRadiusDamageType(actor, act2->spr.extra);
+
+					if (!(actor->flags3 & SFLAG3_HITRADIUS_NODAMAGE))
+					{
+						if (dist < radius / 3)
+						{
+							if (hp4 == hp3) hp4++;
+							act2->hitextra = hp3 + (krand() % (hp4 - hp3));
+						}
+						else if (dist < 2 * radius / 3)
+						{
+							if (hp3 == hp2) hp3++;
+							act2->hitextra = hp2 + (krand() % (hp3 - hp2));
+						}
+						else if (dist < radius)
+						{
+							if (hp2 == hp1) hp2++;
+							act2->hitextra = hp1 + (krand() % (hp2 - hp1));
+						}
+
+						if (!(act2->flags2 & SFLAG2_NORADIUSPUSH) && !bossguy(act2))
+						{
+							if (act2->vel.X < 0) act2->vel.X = 0;
+							act2->vel.X += ((actor->spr.extra / 4.));
+						}
+
+						if ((act2->flags1 & SFLAG_HITRADIUSCHECK))
+							checkhitsprite(act2, actor);
+					}
+					else if (actor->spr.extra == 0) act2->hitextra = 0;
+
+					if (act2->GetClass() != DukeRadiusExplosionClass && Owner && Owner->spr.statnum < MAXSTATUS)
+					{
+						if (act2->isPlayer())
+						{
+							int p = act2->PlayerIndex();
+
+							if (act2->attackertype == DukeFlamethrowerFlameClass && Owner->isPlayer())
+							{
+								ps[p].numloogs = -1 - actor->spr.yint;
+							}
+
+							if (ps[p].newOwner != nullptr)
+							{
+								clearcamera(&ps[p]);
+							}
+						}
+						act2->SetHitOwner(actor->GetOwner());
+					}
+				}
+			}
+		}
+	}
+}
+
 //---------------------------------------------------------------------------
 //
 // Rotating sector
diff --git a/source/games/duke/src/actors_d.cpp b/source/games/duke/src/actors_d.cpp
index 135b8ad58..9ab5d01a6 100644
--- a/source/games/duke/src/actors_d.cpp
+++ b/source/games/duke/src/actors_d.cpp
@@ -147,120 +147,6 @@ int ifsquished(DDukeActor* actor, int p)
 //
 //---------------------------------------------------------------------------
 
-void hitradius_d(DDukeActor* actor, int  r, int  hp1, int  hp2, int  hp3, int  hp4)
-{
-	double radius = r * inttoworld;
-	static const uint8_t statlist[] = { STAT_DEFAULT, STAT_ACTOR, STAT_STANDABLE, STAT_PLAYER, STAT_FALLER, STAT_ZOMBIEACTOR, STAT_MISC };
-
-	if(!(actor->flags3 & SFLAG3_NOCEILINGBLAST))
-	{
-		blastceiling(actor, radius);
-	}
-
-	double q = zrand(32) - 16;
-
-	auto Owner = actor->GetOwner();
-	for (int x = 0; x < 7; x++)
-	{
-		DukeStatIterator itj(statlist[x]);
-		while (auto act2 = itj.Next())
-		{
-			if (Owner)
-			{
-				if (Owner->isPlayer() && act2->isPlayer() && ud.coop != 0 && ud.ffire == 0 && Owner != act2 /* && (dmflags & NOFRIENDLYRADIUSDMG)*/)
-				{
-					continue;
-				}
-
-				if (actor->flags3 & SFLAG3_HITRADIUS_DONTHURTSPECIES && !Owner->isPlayer() && Owner->GetClass() == act2->GetClass())
-				{
-					continue;
-				}
-			}
-
-			if (x == 0 || x >= 5 || (act2->flags1 & SFLAG_HITRADIUS_CHECKHITONLY))
-			{
-				if (!(actor->flags3 & SFLAG3_HITRADIUS_NODAMAGE) || (act2->spr.cstat & CSTAT_SPRITE_BLOCK_ALL))
-					if ((actor->spr.pos - act2->spr.pos).Length() < radius)
-					{
-						if (badguy(act2) && !cansee(act2->spr.pos.plusZ(q), act2->sector(), actor->spr.pos.plusZ(q), actor->sector()))
-							continue;
-						checkhitsprite(act2, actor);
-					}
-			}
-			else if (act2->spr.extra >= 0 && act2 != actor && ((act2->flags1 & SFLAG_HITRADIUS_FORCEEFFECT) || badguy(act2) || (act2->spr.cstat & CSTAT_SPRITE_BLOCK_ALL)))
-			{
-				if (actor->flags3 & SFLAG3_HITRADIUS_DONTHURTSHOOTER && act2 == Owner)
-				{
-					continue;
-				}
-
-				double dist = (act2->getPosWithOffsetZ() - actor->spr.pos).Length();
-
-				if (dist < radius && cansee(act2->spr.pos.plusZ(-8), act2->sector(), actor->spr.pos.plusZ(-12), actor->sector()))
-				{
-					act2->hitang = (act2->spr.pos - actor->spr.pos).Angle();
-					act2->attackertype = CallGetRadiusDamageType(actor, act2->spr.extra);
-
-					if (!(actor->flags3 & SFLAG3_HITRADIUS_NODAMAGE))
-					{
-						if (dist < radius / 3)
-						{
-							if (hp4 == hp3) hp4++;
-							act2->hitextra = hp3 + (krand() % (hp4 - hp3));
-						}
-						else if (dist < 2 * radius / 3)
-						{
-							if (hp3 == hp2) hp3++;
-							act2->hitextra = hp2 + (krand() % (hp3 - hp2));
-						}
-						else if (dist < radius)
-						{
-							if (hp2 == hp1) hp2++;
-							act2->hitextra = hp1 + (krand() % (hp2 - hp1));
-						}
-
-						if (!(act2->flags2 & SFLAG2_NORADIUSPUSH) && !bossguy(act2))
-						{
-							if (act2->vel.X < 0) act2->vel.X = 0;
-							act2->vel.X += ( (actor->spr.extra / 4.));
-						}
-
-						if ((act2->flags1 & SFLAG_HITRADIUSCHECK))
-							checkhitsprite(act2, actor);
-					}
-					else if (actor->spr.extra == 0) act2->hitextra = 0;
-
-					if (act2->GetClass() != DukeRadiusExplosionClass && Owner && Owner->spr.statnum < MAXSTATUS)
-					{
-						if (act2->isPlayer())
-						{
-							int p = act2->PlayerIndex();
-
-							if (act2->attackertype == DukeFlamethrowerFlameClass && Owner->isPlayer())
-							{
-								ps[p].numloogs = -1 - actor->spr.yint;
-							}
-
-							if (ps[p].newOwner != nullptr)
-							{
-								clearcamera(&ps[p]);
-							}
-						}
-						act2->SetHitOwner(actor->GetOwner());
-					}
-				}
-			}
-		}
-	}
-}
-
-//---------------------------------------------------------------------------
-//
-// 
-//
-//---------------------------------------------------------------------------
-
 
 int movesprite_ex_d(DDukeActor* actor, const DVector3& change, unsigned int cliptype, Collision &result)
 {
diff --git a/source/games/duke/src/actors_r.cpp b/source/games/duke/src/actors_r.cpp
index 03011354f..a6dbd630d 100644
--- a/source/games/duke/src/actors_r.cpp
+++ b/source/games/duke/src/actors_r.cpp
@@ -146,102 +146,6 @@ void addweapon_r(player_struct* p, int weapon, bool wswitch)
 //
 //---------------------------------------------------------------------------
 
-void hitradius_r(DDukeActor* actor, int  r, int  hp1, int  hp2, int  hp3, int  hp4)
-{
-	double radius = r * inttoworld;
-	static const uint8_t statlist[] = { STAT_DEFAULT, STAT_ACTOR, STAT_STANDABLE, STAT_PLAYER, STAT_FALLER, STAT_ZOMBIEACTOR, STAT_MISC };
-
-	if (!(actor->flags3 & SFLAG3_NOCEILINGBLAST))
-	{
-		blastceiling(actor, radius);
-	}
-
-	double q = zrand(32) - 24;
-
-	auto Owner = actor->GetOwner();
-	for (int x = 0; x < 7; x++)
-	{
-		DukeStatIterator it1(statlist[x]);
-		while (auto act2 = it1.Next())
-		{
-			if (x == 0 || x >= 5 || (act2->flags1 & SFLAG_HITRADIUS_CHECKHITONLY))
-			{
-				if ((actor->spr.pos - act2->spr.pos).Length() < radius)
-				{
-					if (badguy(act2) && !cansee(act2->spr.pos.plusZ(q), act2->sector(), actor->spr.pos.plusZ(q), actor->sector()))
-						continue;
-
-					checkhitsprite(act2, actor);
-				}
-			}
-			else if (act2->spr.extra >= 0 && act2 != actor && ((act2->flags1 & SFLAG_HITRADIUS_FORCEEFFECT) || badguy(act2) || (act2->spr.cstat & CSTAT_SPRITE_BLOCK_ALL)))
-			{
-				if (actor->flags3 & SFLAG3_HITRADIUS_DONTHURTSHOOTER && act2 == Owner)
-				{
-					continue;
-				}
-				if (actor->flags3 & SFLAG3_HITRADIUS_NOEFFECT)
-				{
-					continue;
-				}
-
-				double dist = (act2->getPosWithOffsetZ() - actor->spr.pos).Length();
-
-				if (dist < radius && cansee(act2->spr.pos.plusZ(-8), act2->sector(), actor->spr.pos.plusZ(-12), actor->sector()))
-				{
-
-					act2->hitang = (act2->spr.pos - actor->spr.pos).Angle();
-					act2->attackertype = CallGetRadiusDamageType(actor, act2->spr.extra);
-
-					if (dist < radius / 3)
-					{
-						if (hp4 == hp3) hp4++;
-						act2->hitextra = hp3 + (krand() % (hp4 - hp3));
-					}
-					else if (dist < 2 * radius / 3)
-					{
-						if (hp3 == hp2) hp3++;
-						act2->hitextra = hp2 + (krand() % (hp3 - hp2));
-					}
-					else if (dist < radius)
-					{
-						if (hp2 == hp1) hp2++;
-						act2->hitextra = hp1 + (krand() % (hp2 - hp1));
-					}
-
-					if (!(act2->flags2 & SFLAG2_NORADIUSPUSH) && !bossguy(act2))
-					{
-						if (act2->vel.X < 0) act2->vel.X = 0;
-						act2->vel.X += ((actor->spr.extra / 4.));
-					}
-
-					if ((act2->flags1 & SFLAG_HITRADIUSCHECK))
-						checkhitsprite(act2, actor);
-
-					if (act2->GetClass() != DukeRadiusExplosionClass && Owner && Owner->spr.statnum < MAXSTATUS)
-					{
-						if (act2->isPlayer())
-						{
-							int p = act2->PlayerIndex();
-							if (ps[p].newOwner != nullptr)
-							{
-								clearcamera(&ps[p]);
-							}
-						}
-						act2->SetHitOwner(actor->GetOwner());
-					}
-				}
-			}
-		}
-	}
-}
-
-//---------------------------------------------------------------------------
-//
-// 
-//
-//---------------------------------------------------------------------------
-
 int movesprite_ex_r(DDukeActor* actor, const DVector3& change, unsigned int cliptype, Collision &result)
 {
 	int bg = badguy(actor);
diff --git a/source/games/duke/src/dispatch.cpp b/source/games/duke/src/dispatch.cpp
index 62362b2c9..160b72fd1 100644
--- a/source/games/duke/src/dispatch.cpp
+++ b/source/games/duke/src/dispatch.cpp
@@ -46,8 +46,6 @@ void checksectors_r(int snum);
 
 void addweapon_d(player_struct* p, int weapon, bool wswitch);
 void addweapon_r(player_struct* p, int weapon, bool wswitch);
-void hitradius_d(DDukeActor* i, int  r, int  hp1, int  hp2, int  hp3, int  hp4);
-void hitradius_r(DDukeActor* i, int  r, int  hp1, int  hp2, int  hp3, int  hp4);
 void lotsofmoney_d(DDukeActor* s, int n);
 void lotsofmail_d(DDukeActor* s, int n);
 void lotsofpaper_d(DDukeActor* s, int n);
@@ -97,7 +95,6 @@ void SetDispatcher()
 		checksectors_d,
 
 		addweapon_d,
-		hitradius_d,
 		lotsofmoney_d,
 		lotsofmail_d,
 		lotsofpaper_d,
@@ -128,7 +125,6 @@ void SetDispatcher()
 		checksectors_r,
 
 		addweapon_r,
-		hitradius_r,
 		lotsoffeathers_r,
 		lotsoffeathers_r,
 		lotsoffeathers_r,
diff --git a/source/games/duke/src/duke3d.h b/source/games/duke/src/duke3d.h
index e42d6028a..0a41abec9 100644
--- a/source/games/duke/src/duke3d.h
+++ b/source/games/duke/src/duke3d.h
@@ -81,7 +81,6 @@ struct Dispatcher
 	void (*checksectors)(int low);
 
 	void (*addweapon)(player_struct *p, int weapon, bool wswitch);
-	void (*hitradius)(DDukeActor* i, int  r, int  hp1, int  hp2, int  hp3, int  hp4);
 	void (*lotsofmoney)(DDukeActor *s, int n);
 	void (*lotsofmail)(DDukeActor *s, int n);
 	void (*lotsofpaper)(DDukeActor *s, int n);
diff --git a/source/games/duke/src/funct.h b/source/games/duke/src/funct.h
index 39234bcbb..fe9668e4a 100644
--- a/source/games/duke/src/funct.h
+++ b/source/games/duke/src/funct.h
@@ -40,7 +40,7 @@ void movefta();
 void clearcameras(player_struct* p);
 void RANDOMSCRAP(DDukeActor* i);
 void detonate(DDukeActor* i, PClassActor* explosion);
-void blastceiling(DDukeActor* actor, double radius);
+void hitradius(DDukeActor* i, int  r, int  hp1, int  hp2, int  hp3, int  hp4);
 void lotsofstuff(DDukeActor* s, int n, PClassActor* spawntype);
 void watersplash2(DDukeActor* i);
 bool money(DDukeActor* i, int BLOODPOOL);
diff --git a/source/games/duke/src/gameexec.cpp b/source/games/duke/src/gameexec.cpp
index 6fe576fa6..10d708f4d 100644
--- a/source/games/duke/src/gameexec.cpp
+++ b/source/games/duke/src/gameexec.cpp
@@ -2017,7 +2017,7 @@ int ParseState::parse(void)
 		insptr += 2;
 		break;
 	case concmd_hitradius:
-		fi.hitradius(g_ac, *(insptr + 1), *(insptr + 2), *(insptr + 3), *(insptr + 4), *(insptr + 5));
+		hitradius(g_ac, *(insptr + 1), *(insptr + 2), *(insptr + 3), *(insptr + 4), *(insptr + 5));
 		insptr+=6;
 		break;
 	case concmd_ifp:
diff --git a/source/games/duke/src/vmexports.cpp b/source/games/duke/src/vmexports.cpp
index 9cee600da..ae3d177a8 100644
--- a/source/games/duke/src/vmexports.cpp
+++ b/source/games/duke/src/vmexports.cpp
@@ -549,12 +549,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, RandomScrap, RANDOMSCRAP)
 	return 0;
 }
 
-void DukeActor_hitradius(DDukeActor* actor, int  r, int  hp1, int  hp2, int  hp3, int  hp4)
-{
-	fi.hitradius(actor, r, hp1, hp2, hp3, hp4);
-}
-
-DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, hitradius, DukeActor_hitradius)
+DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, hitradius, hitradius)
 {
 	PARAM_SELF_PROLOGUE(DDukeActor);
 	PARAM_INT(r);
@@ -562,7 +557,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DDukeActor, hitradius, DukeActor_hitradius)
 	PARAM_INT(h2);
 	PARAM_INT(h3);
 	PARAM_INT(h4);
-	DukeActor_hitradius(self, r, h1, h2, h3, h4);
+	hitradius(self, r, h1, h2, h3, h4);
 	return 0;
 }