Maelstrom: Fixed game over timing for deathmatch multiplayer games

From 9eeb95d0ff9d9347e453ae35fdaa2ab693618416 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 28 Apr 2026 03:21:29 -0700
Subject: [PATCH] Fixed game over timing for deathmatch multiplayer games

It's now possible for there to be more frags than expected or ties in a 3-player deathmatch, but the match ends much more gracefully.
---
 game/player.cpp | 98 +++++++++++++++++++++++++++++--------------------
 game/player.h   |  2 +
 2 files changed, 61 insertions(+), 39 deletions(-)

diff --git a/game/player.cpp b/game/player.cpp
index 555c9abb..28a8c649 100644
--- a/game/player.cpp
+++ b/game/player.cpp
@@ -239,17 +239,6 @@ void
 Player::IncrFrags(void)
 {
 	++Frags;
-	if ( gGameInfo.IsDeathmatch() && (Frags >= gGameInfo.lives) ) {
-		/* Game over, we got a stud. :) */
-		int i;
-		OBJ_LOOP(i, MAX_PLAYERS) {
-			if (!gPlayers[i]->IsValid()) {
-				continue;
-			}
-			gPlayers[i]->IncrLives(-1);
-			gPlayers[i]->Explode();
-		}
-	}
 }
 
 void
@@ -548,42 +537,73 @@ printf("\n");
 	UpdateCamera();
 
 	/* Check to see if we are dead... */
-	if ( Dead ) {
+	if (Dead) {
 		if (--Dead == 0) {  // New Chance at Life!
-			// If we're the last life in a co-op multiplayer game, we're done
-			if (gGameInfo.IsMultiplayer() && !gGameInfo.IsDeathmatch() && !Lives) {
-				int i;
-				bool allGhosts = true;
-				OBJ_LOOP(i, MAX_PLAYERS) {
-					if (!gPlayers[i]->IsValid() || i == Index) {
-						continue;
-					}
-					if (i != Index && !gPlayers[i]->Ghost) {
-						allGhosts = false;
-						break;
-					}
-				}
-				if (allGhosts) {
-					OBJ_LOOP(i, MAX_PLAYERS) {
-						if (!gPlayers[i]->IsValid()) {
-							continue;
-						}
-						gPlayers[i]->Dead = DEAD_DELAY;
-						gPlayers[i]->Playing = 0;
-					}
-					return (0);
+			HandleDeath();
+		}
+	}
+
+	return result;
+}
+
+void
+Player::HandleDeath()
+{
+	int i;
+
+	// If we're the last life in a co-op multiplayer game, we're done
+	if (gGameInfo.IsMultiplayer() && !gGameInfo.IsDeathmatch() && !Lives) {
+		int i;
+		bool allGhosts = true;
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
+			if (i != Index && !gPlayers[i]->Ghost) {
+				allGhosts = false;
+				break;
+			}
+		}
+		if (allGhosts) {
+			OBJ_LOOP(i, MAX_PLAYERS) {
+				if (!gPlayers[i]->IsValid()) {
+					continue;
 				}
+				gPlayers[i]->Dead = DEAD_DELAY;
+				gPlayers[i]->Playing = 0;
 			}
+			return;
+		}
+	}
 
-			if ( NewShip() < 0 ) {
-				/* Game Over */
-				Dead = DEAD_DELAY;
-				Playing = 0;
+	// If we're the last frag in a deathmatch multiplayer game, we're done
+	if (gGameInfo.IsMultiplayer() && gGameInfo.IsDeathmatch()) {
+		bool gameover = false;
+		OBJ_LOOP(i, MAX_PLAYERS) {
+			if (!gPlayers[i]->IsValid()) {
+				continue;
+			}
+			if (gPlayers[i]->Frags >= gGameInfo.lives) {
+				gameover = true;
+			}
+		}
+		if (gameover) {
+			OBJ_LOOP(i, MAX_PLAYERS) {
+				if (!gPlayers[i]->IsValid()) {
+					continue;
+				}
+				gPlayers[i]->Dead = DEAD_DELAY;
+				gPlayers[i]->Playing = 0;
 			}
+			return;
 		}
 	}
 
-	return result;
+	if ( NewShip() < 0 ) {
+		/* Game Over */
+		Dead = DEAD_DELAY;
+		Playing = 0;
+	}
 }
 
 void
diff --git a/game/player.h b/game/player.h
index 05299fe8..bb5064cf 100644
--- a/game/player.h
+++ b/game/player.h
@@ -174,6 +174,8 @@ class Player : public Object {
 		*Y = CameraY;
 	}
 
+	void HandleDeath();
+
 private:
 	int Valid;
 	int Index;