From 18e43a5cef6a45ee1f4c5c779bcf8e48ff9e7d65 Mon Sep 17 00:00:00 2001
From: toaster <rollerorbital@gmail.com>
Date: Tue, 30 Jul 2019 16:44:40 +0100
Subject: [PATCH] * Fix "exitlevel" being counted as a special stage success
 despite not giving you an emerald by inverting stagefailed's default value,
 since there's only a limited number of ways you can WIN at a special stage. *
 Correct a potential source of desync in P_GiveEmerald.

---
 src/p_inter.c |  3 +++
 src/p_setup.c |  2 +-
 src/p_tick.c  |  3 ---
 src/p_user.c  | 37 ++++++++++++++++++++++++++++++-------
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/src/p_inter.c b/src/p_inter.c
index abf33429fa..486c39fb7f 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -670,7 +670,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				P_DoMatchSuper(player);
 			}
 			else
+			{
 				emeralds |= special->info->speed;
+				stagefailed = false;
+			}
 
 			if (special->target && special->target->type == MT_EMERALDSPAWN)
 			{
diff --git a/src/p_setup.c b/src/p_setup.c
index c0aa7ffa35..976d191905 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2215,7 +2215,7 @@ static void P_LevelInitStuff(void)
 	ssspheres = timeinmap = 0;
 
 	// special stage
-	stagefailed = false;
+	stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial
 	// Reset temporary record data
 	memset(&ntemprecords, 0, sizeof(nightsdata_t));
 
diff --git a/src/p_tick.c b/src/p_tick.c
index a0f6edef9b..cfdd54eb20 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -518,10 +518,7 @@ static inline void P_DoSpecialStageStuff(void)
 			}
 		}
 		else
-		{
 			sstimer = 0;
-			stagefailed = true;
-		}
 	}
 }
 
diff --git a/src/p_user.c b/src/p_user.c
index b758cebe49..cdf8c246c7 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -302,15 +302,39 @@ void P_GiveEmerald(boolean spawnObj)
 
 	S_StartSound(NULL, sfx_cgot); // Got the emerald!
 	emeralds |= (1 << em);
+	stagefailed = false;
 
-	if (spawnObj && playeringame[consoleplayer])
+	if (spawnObj)
 	{
 		// The Chaos Emerald begins to orbit us!
-		// Only give it to ONE person!
-		mobj_t *emmo = P_SpawnMobjFromMobj(players[consoleplayer].mo, 0, 0, players[consoleplayer].mo->height, MT_GOTEMERALD);
-		P_SetTarget(&emmo->target, players[consoleplayer].mo);
-		P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
-		P_SetTarget(&players[consoleplayer].mo->tracer, emmo);
+		// Only visibly give it to ONE person!
+		UINT8 i, pnum = ((playeringame[consoleplayer]) && (!players[consoleplayer].spectator) && (players[consoleplayer].mo)) ? consoleplayer : 255;
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			mobj_t *emmo;
+			if (!playeringame[i])
+				continue;
+			if (players[i].spectator)
+				continue;
+			if (!players[i].mo)
+				continue;
+
+			emmo = P_SpawnMobjFromMobj(players[i].mo, 0, 0, players[i].mo->height, MT_GOTEMERALD);
+			P_SetTarget(&emmo->target, players[i].mo);
+			P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
+			P_SetTarget(&players[i].mo->tracer, emmo);
+
+			if (pnum == 255)
+			{
+				i = pnum;
+				continue;
+			}
+
+			if (i == pnum)
+				continue;
+
+			emmo->flags2 |= MF2_DONTDRAW;
+		}
 	}
 }
 
@@ -615,7 +639,6 @@ static void P_DeNightserizePlayer(player_t *player)
 			if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
 				players[i].nightstime = 1; // force everyone else to fall too.
 		player->exiting = 3*TICRATE;
-		stagefailed = true; // NIGHT OVER
 
 		// If you screwed up, kiss your score and ring bonus goodbye.
 		// But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground.
-- 
GitLab