From f241d9773a795551063f75ecf248c8d21ec80b16 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Wed, 25 May 2016 11:30:11 +0200
Subject: [PATCH] - made P_NoiseAlert non-recursive to avoid stack overflow
 problems in large open-area maps with a high sector count.

---
 src/p_enemy.cpp                   | 82 ++++++++++++++++++-------------
 src/p_enemy.h                     |  1 -
 src/thingdef/thingdef_codeptr.cpp |  3 +-
 3 files changed, 50 insertions(+), 36 deletions(-)

diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp
index 585c292f8..227c1ab48 100644
--- a/src/p_enemy.cpp
+++ b/src/p_enemy.cpp
@@ -120,30 +120,32 @@ void P_RandomChaseDir (AActor *actor);
 // PROC P_RecursiveSound
 //
 // Called by P_NoiseAlert.
-// Recursively traverse adjacent sectors,
+// Traverses adjacent sectors,
 // sound blocking lines cut off traversal.
 //----------------------------------------------------------------------------
 
-void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soundblocks, AActor *emitter, double maxdist)
+struct NoiseTarget
+{
+	sector_t *sec;
+	int soundblocks;
+};
+static TArray<NoiseTarget> NoiseList(128);
+
+static void NoiseMarkSector(sector_t *sec, AActor *soundtarget, bool splash, AActor *emitter, int soundblocks, double maxdist)
 {
-	int 		i;
-	line_t* 	check;
-	sector_t*	other;
-	AActor*		actor;
-		
 	// wake up all monsters in this sector
 	if (sec->validcount == validcount
-		&& sec->soundtraversed <= soundblocks+1)
+		&& sec->soundtraversed <= soundblocks + 1)
 	{
 		return; 		// already flooded
 	}
-	
+
 	sec->validcount = validcount;
-	sec->soundtraversed = soundblocks+1;
+	sec->soundtraversed = soundblocks + 1;
 	sec->SoundTarget = soundtarget;
 
 	// [RH] Set this in the actors in the sector instead of the sector itself.
-	for (actor = sec->thinglist; actor != NULL; actor = actor->snext)
+	for (AActor *actor = sec->thinglist; actor != NULL; actor = actor->snext)
 	{
 		if (actor != soundtarget && (!splash || !(actor->flags4 & MF4_NOSPLASHALERT)) &&
 			(!maxdist || (actor->Distance2D(emitter) <= maxdist)))
@@ -151,31 +153,39 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun
 			actor->LastHeard = soundtarget;
 		}
 	}
+	NoiseList.Push({ sec, soundblocks });
+}
 
+
+static void P_RecursiveSound(sector_t *sec, AActor *soundtarget, bool splash, AActor *emitter, int soundblocks, double maxdist)
+{
 	bool checkabove = !sec->PortalBlocksSound(sector_t::ceiling);
 	bool checkbelow = !sec->PortalBlocksSound(sector_t::floor);
 
-	for (i = 0; i < sec->linecount; i++)
+	for (int i = 0; i < sec->linecount; i++)
 	{
-		check = sec->lines[i];
+		line_t *check = sec->lines[i];
 
+		// check sector portals
 		// I wish there was a better method to do this than randomly looking through the portal at a few places...
 		if (checkabove)
 		{
 			sector_t *upper = P_PointInSector(check->v1->fPos() + check->Delta() / 2 + sec->GetPortalDisplacement(sector_t::ceiling));
-			P_RecursiveSound(upper, soundtarget, splash, soundblocks, emitter, maxdist);
+			NoiseMarkSector(upper, soundtarget, splash, emitter, soundblocks, maxdist);
 		}
 		if (checkbelow)
 		{
 			sector_t *lower = P_PointInSector(check->v1->fPos() + check->Delta() / 2 + sec->GetPortalDisplacement(sector_t::floor));
-			P_RecursiveSound(lower, soundtarget, splash, soundblocks, emitter, maxdist);
+			NoiseMarkSector(lower, soundtarget, splash, emitter, soundblocks, maxdist);
 		}
+
+		// ... and line portals;
 		FLinePortal *port = check->getPortal();
 		if (port && (port->mFlags & PORTF_SOUNDTRAVERSE))
 		{
 			if (port->mDestination)
 			{
-				P_RecursiveSound(port->mDestination->frontsector, soundtarget, splash, soundblocks, emitter, maxdist);
+				NoiseMarkSector(port->mDestination->frontsector, soundtarget, splash, emitter, soundblocks, maxdist);
 			}
 		}
 
@@ -185,28 +195,29 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun
 		{
 			continue;
 		}
-		
+
 		// Early out for intra-sector lines
 		if (check->sidedef[0]->sector == check->sidedef[1]->sector) continue;
 
-		if ( check->sidedef[0]->sector == sec)
+		sector_t *other;
+		if (check->sidedef[0]->sector == sec)
 			other = check->sidedef[1]->sector;
 		else
 			other = check->sidedef[0]->sector;
 
 		// check for closed door
-		if ((sec->floorplane.ZatPoint (check->v1->fPos()) >=
-			 other->ceilingplane.ZatPoint (check->v1->fPos()) &&
-			 sec->floorplane.ZatPoint (check->v2->fPos()) >=
-			 other->ceilingplane.ZatPoint (check->v2->fPos()))
-		 || (other->floorplane.ZatPoint (check->v1->fPos()) >=
-			 sec->ceilingplane.ZatPoint (check->v1->fPos()) &&
-			 other->floorplane.ZatPoint (check->v2->fPos()) >=
-			 sec->ceilingplane.ZatPoint (check->v2->fPos()))
-		 || (other->floorplane.ZatPoint (check->v1->fPos()) >=
-			 other->ceilingplane.ZatPoint (check->v1->fPos()) &&
-			 other->floorplane.ZatPoint (check->v2->fPos()) >=
-			 other->ceilingplane.ZatPoint (check->v2->fPos())))
+		if ((sec->floorplane.ZatPoint(check->v1->fPos()) >=
+			other->ceilingplane.ZatPoint(check->v1->fPos()) &&
+			sec->floorplane.ZatPoint(check->v2->fPos()) >=
+			other->ceilingplane.ZatPoint(check->v2->fPos()))
+			|| (other->floorplane.ZatPoint(check->v1->fPos()) >=
+				sec->ceilingplane.ZatPoint(check->v1->fPos()) &&
+				other->floorplane.ZatPoint(check->v2->fPos()) >=
+				sec->ceilingplane.ZatPoint(check->v2->fPos()))
+			|| (other->floorplane.ZatPoint(check->v1->fPos()) >=
+				other->ceilingplane.ZatPoint(check->v1->fPos()) &&
+				other->floorplane.ZatPoint(check->v2->fPos()) >=
+				other->ceilingplane.ZatPoint(check->v2->fPos())))
 		{
 			continue;
 		}
@@ -214,17 +225,18 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun
 		if (check->flags & ML_SOUNDBLOCK)
 		{
 			if (!soundblocks)
-				P_RecursiveSound (other, soundtarget, splash, 1, emitter, maxdist);
+				NoiseMarkSector(other, soundtarget, splash, emitter, 1, maxdist);
 		}
 		else
 		{
-			P_RecursiveSound (other, soundtarget, splash, soundblocks, emitter, maxdist);
+			NoiseMarkSector(other, soundtarget, splash, emitter, soundblocks, maxdist);
 		}
 	}
 }
 
 
 
+
 //----------------------------------------------------------------------------
 //
 // PROC P_NoiseAlert
@@ -243,7 +255,11 @@ void P_NoiseAlert (AActor *target, AActor *emitter, bool splash, double maxdist)
 		return;
 
 	validcount++;
-	P_RecursiveSound (emitter->Sector, target, splash, 0, emitter, maxdist);
+	NoiseMarkSector(emitter->Sector, target, splash, emitter, 0, maxdist);
+	for (unsigned i = 0; i < NoiseList.Size(); i++)
+	{
+		P_RecursiveSound(NoiseList[i].sec, target, splash, emitter, NoiseList[i].soundblocks, maxdist);
+	}
 }
 
 
diff --git a/src/p_enemy.h b/src/p_enemy.h
index 298c60725..1be77a4ec 100644
--- a/src/p_enemy.h
+++ b/src/p_enemy.h
@@ -46,7 +46,6 @@ struct FLookExParams
 };
 
 void P_DaggerAlert (AActor *target, AActor *emitter);
-void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soundblocks, AActor *emitter=NULL, double maxdist=0);
 bool P_HitFriend (AActor *self);
 void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash=false, double maxdist=0);
 
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index e003277ad..feec1aceb 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -1226,8 +1226,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
 	P_CheckSplash(self, distance);
 	if (alert && self->target != NULL && self->target->player != NULL)
 	{
-		validcount++;
-		P_RecursiveSound (self->Sector, self->target, false, 0);
+		P_NoiseAlert(self->target, self);
 	}
 	return 0;
 }