Maelstrom: Fixed respawn and wave end timing

From 6ffe73e9c2fd839da6caa235f000127f50d9581c Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 28 Apr 2026 00:18:16 -0700
Subject: [PATCH] Fixed respawn and wave end timing

The death timer starts as soon as the player explodes. The next wave timer starts as soon as the last asteroid explodes. We carefully time these so if they happen at the same time, the player stays alive.
---
 game/game.cpp    |  8 +++++---
 game/objects.cpp |  3 ---
 game/objects.h   | 15 +++++----------
 game/player.cpp  | 30 ++++++++++++------------------
 game/replay.h    |  2 +-
 5 files changed, 23 insertions(+), 35 deletions(-)

diff --git a/game/game.cpp b/game/game.cpp
index ea2bd917..e89c71e5 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -1120,10 +1120,12 @@ GamePanelDelegate::DoHousekeeping()
 
 	/* -- Time for the next wave? */
 	if (gNumRocks == 0) {
-		if ( gWhenDone == 0 )
-			gWhenDone = DEAD_DELAY;
-		else if ( --gWhenDone == 0 )
+		if (gWhenDone == 0) {
+			gWhenDone = DEAD_DELAY - 1;
+		}
+		if (--gWhenDone == 0) {
 			NextWave();
+		}
 	}
 
 	/* -- Make sure someone is still playing... */
diff --git a/game/objects.cpp b/game/objects.cpp
index 4d833c43..218bee53 100644
--- a/game/objects.cpp
+++ b/game/objects.cpp
@@ -122,7 +122,6 @@ SmallRock::SmallRock(int X, int Y, int xVel, int yVel, int phaseFreq) :
 		((xVel > 0) ? gRock3R : gRock3L), phaseFreq)
 {
 	Set_Points(SMALL_ROID_PTS);
-	++gNumRocks;
 #ifdef SERIOUS_DEBUG
 error("+   Small rock! (%d)\n", gNumRocks);
 #endif
@@ -133,7 +132,6 @@ MediumRock::MediumRock(int X, int Y, int xVel, int yVel, int phaseFreq) :
 		((xVel > 0) ? gRock2R : gRock2L), phaseFreq)
 {
 	Set_Points(MEDIUM_ROID_PTS);
-	++gNumRocks;
 #ifdef SERIOUS_DEBUG
 error("++  Medium rock! (%d)\n", gNumRocks);
 #endif
@@ -144,7 +142,6 @@ LargeRock::LargeRock(int X, int Y, int xVel, int yVel, int phaseFreq) :
 		((xVel > 0) ? gRock1R : gRock1L), phaseFreq)
 {
 	Set_Points(BIG_ROID_PTS);
-	++gNumRocks;
 #ifdef SERIOUS_DEBUG
 error("+++ Large rock! (%d)\n", gNumRocks);
 #endif
diff --git a/game/objects.h b/game/objects.h
index 8fdda619..8e2c5962 100644
--- a/game/objects.h
+++ b/game/objects.h
@@ -437,7 +437,9 @@ class Homing : public Object {
 
 class Rock : public Object {
 public:
-	Rock(int X, int Y, int Xvec, int Yvec, Blit *blit, int PhaseTime) : Object(X, Y, Xvec, Yvec, blit, PhaseTime) { }
+	Rock(int X, int Y, int Xvec, int Yvec, Blit *blit, int PhaseTime) : Object(X, Y, Xvec, Yvec, blit, PhaseTime) {
+		++gNumRocks;
+	}
 
 	virtual int IsRock(void) {
 		return(1);
@@ -455,6 +457,8 @@ class Rock : public Object {
 	virtual int Explode() {
 		int result = Object::Explode();
 
+		--gNumRocks;
+
 		if (gNumSmallRocksDestroyed == 0) {
 			int i;
 
@@ -484,9 +488,6 @@ class SmallRock : public Rock {
 
 public:
 	SmallRock(int X, int Y, int xVel, int yVel, int phaseFreq);
-	~SmallRock() {
-		--gNumRocks;
-	}
 
 	virtual int IsSmallRock(void) {
 		return(1);
@@ -515,9 +516,6 @@ class MediumRock : public Rock {
 
 public:
 	MediumRock(int X, int Y, int xVel, int yVel, int phaseFreq);
-	~MediumRock() {
-		--gNumRocks;
-	}
 
 	virtual int IsMediumRock(void) {
 		return(1);
@@ -576,9 +574,6 @@ class LargeRock : public Rock {
 
 public:
 	LargeRock(int X, int Y, int xVel, int yVel, int phaseFreq);
-	~LargeRock() {
-		--gNumRocks;
-	}
 
 	virtual int IsLargeRock(void) {
 		return(1);
diff --git a/game/player.cpp b/game/player.cpp
index c5715f84..d1ec1efb 100644
--- a/game/player.cpp
+++ b/game/player.cpp
@@ -314,10 +314,6 @@ Player::BeenTimedOut(void)
 {
 	Exploding = 0;
 	SetSpawnPosition();
-	if ( gGameInfo.IsDeathmatch() )
-		Dead = (DEAD_DELAY/2);
-	else
-		Dead = DEAD_DELAY;
 
 	// If we're the last life in a co-op multiplayer game, we're done
 	if (gGameInfo.IsMultiplayer() && !gGameInfo.IsDeathmatch() && !Lives) {
@@ -405,6 +401,7 @@ Player::Explode(void)
 	Set_Blit(gShipExplosion);
 	Set_TTL(myblit->numFrames*phasetime);
 	ExplodeSound();
+	Dead = DEAD_DELAY;
 	AddSteamTimelineEvent(STEAM_TIMELINE_EVENT_DEATH);
 	return(0);
 }
@@ -483,20 +480,6 @@ printf("\n");
 	if ( NoThrust )
 		--NoThrust;
 
-	/* Check to see if we are dead... */
-	if ( Dead ) {
-		UpdateCamera();
-
-		if ( --Dead == 0 ) {  // New Chance at Life!
-			if ( NewShip() < 0 ) {
-				/* Game Over */
-				Dead = DEAD_DELAY;
-				Playing = 0;
-			}
-		}
-		return(0);
-	}
-
 	/* Update our status... :-) */
 	if ( Alive() && ! Exploding ) {
 		/* Airbrakes slow us down. :) */
@@ -585,6 +568,17 @@ printf("\n");
 
 	UpdateCamera();
 
+	/* Check to see if we are dead... */
+	if ( Dead ) {
+		if ( --Dead == 0 ) {  // New Chance at Life!
+			if ( NewShip() < 0 ) {
+				/* Game Over */
+				Dead = DEAD_DELAY;
+				Playing = 0;
+			}
+		}
+	}
+
 	return result;
 }
 
diff --git a/game/replay.h b/game/replay.h
index f06856ae..7a75c8fd 100644
--- a/game/replay.h
+++ b/game/replay.h
@@ -33,7 +33,7 @@
 //
 // Examples of this would be changing the game play area, game logic, etc.
 //
-#define REPLAY_VERSION	3
+#define REPLAY_VERSION	4
 
 #define REPLAY_DIRECTORY "Games"
 #define REPLAY_FILETYPE "mreplay"