diff --git a/src/g_game.c b/src/g_game.c
index fae311694c0caa193b13131f31891a4b46e8df82..877a4c72e0e1d5d014b72110b03eb5b8190c9232 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -3330,7 +3330,7 @@ void G_AddPlayer(INT32 playernum)
 		p->lives = cv_startinglives.value;
 
 	if ((countplayers && !notexiting) || G_IsSpecialStage(gamemap))
-		P_DoPlayerExit(p);
+		P_DoPlayerExit(p, false);
 }
 
 boolean G_EnoughPlayersFinished(void)
@@ -3863,12 +3863,13 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap)
 //
 // G_UpdateVisited
 //
-static void G_UpdateVisited(gamedata_t *data, player_t *player, boolean silent)
+static void G_UpdateVisited(gamedata_t *data, player_t *player, boolean global)
 {
 	// Update visitation flags?
 	if (!demoplayback
 		&& G_CoopGametype() // Campaign mode
-		&& !stagefailed) // Did not fail the stage
+		&& !stagefailed // Did not fail the stage
+		&& (global || player->pflags & PF_FINISHED)) // Actually beat the stage
 	{
 		UINT8 earnedEmblems;
 		UINT16 totalrings = 0;
@@ -3906,12 +3907,12 @@ static void G_UpdateVisited(gamedata_t *data, player_t *player, boolean silent)
 				data->mapvisited[gamemap-1] |= MV_ALLEMERALDS;
 		}
 
-		if ((earnedEmblems = M_CompletionEmblems(data)) && !silent)
+		if ((earnedEmblems = M_CompletionEmblems(data)) && !global)
 		{
 			CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");
 		}
 
-		if (silent)
+		if (global)
 		{
 			M_CheckLevelEmblems(data);
 		}
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 8cb6d185df3910eccf36038ff40f3f9c5670d5c2..063c79dc41b4eb9ebe225bc56399ef76ceaaf4e8 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -1546,11 +1546,12 @@ static int lib_pDoPlayerFinish(lua_State *L)
 static int lib_pDoPlayerExit(lua_State *L)
 {
 	player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
+	boolean finishedflag = lua_opttrueboolean(L, 2);
 	NOHUD
 	INLEVEL
 	if (!player)
 		return LUA_ErrInvalid(L, "player_t");
-	P_DoPlayerExit(player);
+	P_DoPlayerExit(player, finishedflag);
 	return 0;
 }
 
diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c
index 5afa955610a6aee452790fe0ca74b13fc7007d86..12c1b95c6d28ba802155d6230c22905049da6065 100644
--- a/src/netcode/d_netcmd.c
+++ b/src/netcode/d_netcmd.c
@@ -4035,7 +4035,7 @@ static void ExitMove_OnChange(void)
 				if (players[i].mo->target && players[i].mo->target->type == MT_SIGN)
 					P_SetTarget(&players[i].mo->target, NULL);
 
-				if (players[i].pflags & PF_FINISHED)
+				if (players[i].pflags & PF_FINISHED && !(players[i].exiting))
 					P_GiveFinishFlags(&players[i]);
 			}
 
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 93c828fbecd1394e1adbeac6aa3fd43cc43437b6..e210fe1e3f305b614637260f1933823f603782dc 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -3951,7 +3951,7 @@ static void P_DoBossVictory(mobj_t *mo)
 		{
 			if (!playeringame[i])
 				continue;
-			P_DoPlayerExit(&players[i]);
+			P_DoPlayerExit(&players[i], true);
 		}
 	}
 	else
@@ -10820,7 +10820,7 @@ void A_ForceWin(mobj_t *actor)
 	{
 		if (!playeringame[i])
 			continue;
-		P_DoPlayerExit(&players[i]);
+		P_DoPlayerExit(&players[i], true);
 	}
 }
 
diff --git a/src/p_local.h b/src/p_local.h
index 4b330184bddd915ea155ca1741b6b03bf80f43d8..84f33e54a85602d383d4d1f8841e612ce25cb52d 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -188,7 +188,7 @@ void P_DoPityCheck(player_t *player);
 void P_PlayerThink(player_t *player);
 void P_PlayerAfterThink(player_t *player);
 void P_DoPlayerFinish(player_t *player);
-void P_DoPlayerExit(player_t *player);
+void P_DoPlayerExit(player_t *player, boolean finishedflag);
 void P_NightserizePlayer(player_t *player, INT32 ptime);
 
 void P_InstaThrust(mobj_t *mo, angle_t angle, fixed_t move);
diff --git a/src/p_mobj.c b/src/p_mobj.c
index a81845918b64f5ceb74f41f303c43da579bafc55..03c992092562bf55ad24aa54715ea7a59b2392de 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -11715,7 +11715,7 @@ void P_AfterPlayerSpawn(INT32 playernum)
 	if (CheckForReverseGravity)
 		P_CheckGravity(mobj, false);
 
-	if (p->pflags & PF_FINISHED)
+	if (p->pflags & PF_FINISHED && !(p->exiting))
 		P_GiveFinishFlags(p);
 }
 
diff --git a/src/p_spec.c b/src/p_spec.c
index 28ecc60f4dedb5f67f9aa33e092232eb0b3782f6..49b9309471798bb1085789eb2d7c5b681570b8bd 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3662,7 +3662,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 					{
 						if (!playeringame[i])
 							continue;
-						P_DoPlayerExit(&players[i]);
+						P_DoPlayerExit(&players[i], true);
 					}
 				}
 			}
@@ -3716,7 +3716,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 					{
 						if (!playeringame[i])
 							continue;
-						P_DoPlayerExit(&players[i]);
+						P_DoPlayerExit(&players[i], true);
 					}
 				}
 			}
@@ -4477,7 +4477,7 @@ static void P_ProcessEggCapsule(player_t *player, sector_t *sector)
 	{
 		if (!playeringame[i])
 			continue;
-		P_DoPlayerExit(&players[i]);
+		P_DoPlayerExit(&players[i], true);
 	}
 }
 
@@ -4787,7 +4787,7 @@ static void P_ProcessFinishLine(player_t *player)
 			HU_DoCEcho("FINISHED!");
 		}
 
-		P_DoPlayerExit(player);
+		P_DoPlayerExit(player, true);
 	}
 }
 
diff --git a/src/p_user.c b/src/p_user.c
index 24e3f8111d64961ad38f9b26801989539c3fd52e..e41f335cc24e9e1636eec304ac83922e4e9abc2f 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -892,7 +892,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 			players[i].marescore = 0;
 
 			players[i].spheres = players[i].rings = 0;
-			P_DoPlayerExit(&players[i]);
+			P_DoPlayerExit(&players[i], true);
 		}
 	}
 	else if (oldmare != player->mare)
@@ -2188,7 +2188,7 @@ void P_DoPlayerFinish(player_t *player)
 // P_DoPlayerExit
 //
 // Player exits the map via sector trigger
-void P_DoPlayerExit(player_t *player)
+void P_DoPlayerExit(player_t *player, boolean finishedflag)
 {
 	if (player->exiting)
 		return;
@@ -2209,7 +2209,11 @@ void P_DoPlayerExit(player_t *player)
 			player->exiting = (14*TICRATE)/5 + 1;
 	}
 	else
+	{
 		player->exiting = (14*TICRATE)/5 + 2; // Accidental death safeguard???
+		if (finishedflag)
+			player->pflags |= PF_FINISHED; // Give PF_FINISHED as proof of a true finish
+	}
 
 	//player->pflags &= ~PF_GLIDING;
 	if (player->climbing)
@@ -11782,7 +11786,7 @@ void P_PlayerThink(player_t *player)
 		if (((gametyperules & GTR_FRIENDLY) && cv_exitmove.value) && !G_EnoughPlayersFinished())
 			player->exiting = 0;
 		else
-			P_DoPlayerExit(player);
+			P_DoPlayerExit(player, false);
 	}
 
 	// check water content, set stuff in mobj
@@ -11831,7 +11835,7 @@ void P_PlayerThink(player_t *player)
 	}
 
 	// Synchronizes the "real" amount of time spent in the level.
-	if (!player->exiting && !stoppedclock)
+	if (!player->exiting && !(player->pflags & PF_FINISHED) && !stoppedclock)
 	{
 		if (gametyperules & GTR_RACE)
 		{
diff --git a/src/y_inter.c b/src/y_inter.c
index 69dc931ba8cfde0c816baeb8508ce02f758c10bb..453a9c4612a21aa37445e151ac7b47447084ad21 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -2043,7 +2043,7 @@ static void Y_AwardCoopBonuses(void)
 	y_bonus_t localbonuses[4];
 
 	// set score/total first
-	data.coop.total = players[consoleplayer].recordscore;
+	data.coop.total = (players[consoleplayer].pflags & PF_FINISHED) ? players[consoleplayer].recordscore : 0;
 	data.coop.score = players[consoleplayer].score;
 	data.coop.gotperfbonus = -1;
 	memset(data.coop.bonuses, 0, sizeof(data.coop.bonuses));
@@ -2060,7 +2060,12 @@ static void Y_AwardCoopBonuses(void)
 
 		for (j = 0; j < 4; ++j) // Set bonuses
 		{
-			(bonuses_list[bonusnum][j])(&players[i], &localbonuses[j]);
+			//Set the bonus, but only if we actually finished
+			if (players[i].pflags & PF_FINISHED)
+				(bonuses_list[bonusnum][j])(&players[i], &localbonuses[j]);
+			else
+				Y_SetNullBonus(&players[i], &localbonuses[j]);
+			
 			players[i].score += localbonuses[j].points;
 			if (players[i].score > MAXSCORE)
 				players[i].score = MAXSCORE;