From 62927bbb76fc045a8c7a61606ac99f8086d003ac Mon Sep 17 00:00:00 2001
From: toaster <rollerorbital@gmail.com>
Date: Thu, 14 Jun 2018 00:58:28 +0100
Subject: [PATCH] * Hold the pause button to restart a record attack run! *
 Obligatory GIF:
 https://cdn.discordapp.com/attachments/400761370800422922/456586705424875520/srb20047.gif
 * Show powerup display in singleplayer even while holding Game Status button.

---
 src/g_game.c   | 54 +++++++++++++++++++++++++++++++++++++-------------
 src/g_game.h   |  1 +
 src/hu_stuff.c | 23 +++++++++++++++++++++
 src/m_menu.c   |  6 +++---
 src/m_menu.h   |  4 +++-
 src/p_setup.c  | 10 +++++++++-
 src/st_stuff.c |  8 +++++---
 7 files changed, 84 insertions(+), 22 deletions(-)

diff --git a/src/g_game.c b/src/g_game.c
index 2acafddb3c..4463f55ce8 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -1672,7 +1672,7 @@ void G_DoLoadLevel(boolean resetplayer)
 	CON_ClearHUD();
 }
 
-static INT32 pausedelay = 0;
+INT32 pausedelay = 0;
 static INT32 camtoggledelay, camtoggledelay2 = 0;
 
 //
@@ -1822,17 +1822,30 @@ boolean G_Responder(event_t *ev)
 			if (ev->data1 == gamecontrol[gc_pause][0]
 				|| ev->data1 == gamecontrol[gc_pause][1])
 			{
-				if (!pausedelay)
+				if (modeattacking && !demoplayback && (gamestate == GS_LEVEL))
 				{
-					// don't let busy scripts prevent pausing
-					pausedelay = NEWTICRATE/7;
+					if (menuactive || pausedelay < 0 || leveltime < 2)
+						return true;
 
-					// command will handle all the checks for us
-					COM_ImmedExecute("pause");
-					return true;
+					if (++pausedelay > (NEWTICRATE/3))
+					{
+						pausedelay = INT32_MIN;
+						G_SetRetryFlag();
+						return true;
+					}
+					pausedelay++; // counteract subsequent subtraction this frame
 				}
 				else
-					pausedelay = NEWTICRATE/7;
+				{
+					INT32 oldpausedelay = pausedelay;
+					pausedelay = (NEWTICRATE/7);
+					if (!oldpausedelay)
+					{
+						// command will handle all the checks for us
+						COM_ImmedExecute("pause");
+						return true;
+					}
+				}
 			}
 			if (ev->data1 == gamecontrol[gc_camtoggle][0]
 				|| ev->data1 == gamecontrol[gc_camtoggle][1])
@@ -1892,11 +1905,16 @@ void G_Ticker(boolean run)
 		{
 			G_ClearRetryFlag();
 
-			// Costs a life to retry ... unless the player in question is dead already.
-			if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE && players[consoleplayer].lives != 0x7f)
-				players[consoleplayer].lives -= 1;
+			if (modeattacking)
+				M_ModeAttackRetry(0);
+			else
+			{
+				// Costs a life to retry ... unless the player in question is dead already.
+				if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE && players[consoleplayer].lives != 0x7f)
+					players[consoleplayer].lives -= 1;
 
-			G_DoReborn(consoleplayer);
+				G_DoReborn(consoleplayer);
+			}
 		}
 
 		for (i = 0; i < MAXPLAYERS; i++)
@@ -1994,8 +2012,13 @@ void G_Ticker(boolean run)
 
 	if (run)
 	{
-		if (pausedelay)
-			pausedelay--;
+		if (pausedelay && pausedelay != INT32_MIN)
+		{
+			if (pausedelay > 0)
+				pausedelay--;
+			else
+				pausedelay++;
+		}
 
 		if (camtoggledelay)
 			camtoggledelay--;
@@ -2935,6 +2958,9 @@ static void G_DoCompleted(void)
 
 	tokenlist = 0; // Reset the list
 
+	if (modeattacking && pausedelay)
+		pausedelay = 0;
+
 	gameaction = ga_nothing;
 
 	if (metalplayback)
diff --git a/src/g_game.h b/src/g_game.h
index d6b41830e8..3d04370aa0 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -53,6 +53,7 @@ extern INT16 prevmap, nextmap;
 extern INT32 gameovertics;
 extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)
 extern INT16 rw_maximums[NUM_WEAPONS];
+extern INT32 pausedelay;
 
 // used in game menu
 extern consvar_t cv_crosshair, cv_crosshair2;
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index bc57931f5a..f4730005e6 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -1120,6 +1120,29 @@ void HU_Drawer(void)
 
 		V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
 	}
+
+	if (modeattacking && pausedelay > 1)
+	{
+		UINT8 strength = (pausedelay*10)/(NEWTICRATE/3);
+		INT32 y = hudinfo[HUD_LIVES].y - 13;
+
+		if (strength > 9)
+			V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
+		else if (strength)
+			V_DrawFadeScreen(0, strength);
+
+		if (players[consoleplayer].powers[pw_carry] == CR_NIGHTSMODE)
+			y -= 16;
+		else
+		{
+			if (players[consoleplayer].pflags & PF_AUTOBRAKE)
+				y -= 8;
+			if (players[consoleplayer].pflags & PF_ANALOGMODE)
+				y -= 8;
+		}
+
+		V_DrawThinString(hudinfo[HUD_LIVES].x-2, y, hudinfo[HUD_LIVES].f|((leveltime & 2) ? V_SKYMAP : V_BLUEMAP), "RETRYING...");
+	}
 }
 
 //======================================================================
diff --git a/src/m_menu.c b/src/m_menu.c
index a866dac1b9..5258f4b448 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -282,7 +282,6 @@ static void M_Statistics(INT32 choice);
 static void M_ReplayTimeAttack(INT32 choice);
 static void M_ChooseTimeAttack(INT32 choice);
 static void M_ChooseNightsAttack(INT32 choice);
-static void M_ModeAttackRetry(INT32 choice);
 static void M_ModeAttackEndGame(INT32 choice);
 static void M_SetGuestReplay(INT32 choice);
 static void M_HandleChoosePlayerMenu(INT32 choice);
@@ -1083,7 +1082,7 @@ static menuitem_t OP_ChangeControlsMenu[] =
 	{IT_SPACE, NULL, NULL, NULL, 0}, // padding
 	{IT_CALL | IT_STRING2, NULL, "Game Status",
     M_ChangeControl, gc_scores      },
-	{IT_CALL | IT_STRING2, NULL, "Pause",            M_ChangeControl, gc_pause       },
+	{IT_CALL | IT_STRING2, NULL, "Pause / Run Retry", M_ChangeControl, gc_pause       },
 	{IT_CALL | IT_STRING2, NULL, "Console",          M_ChangeControl, gc_console     },
 	{IT_HEADER, NULL, "Multiplayer", NULL, 0},
 	{IT_SPACE, NULL, NULL, NULL, 0}, // padding
@@ -7841,9 +7840,10 @@ static void M_SetGuestReplay(INT32 choice)
 		which(0);
 }
 
-static void M_ModeAttackRetry(INT32 choice)
+void M_ModeAttackRetry(INT32 choice)
 {
 	(void)choice;
+	// todo -- maybe seperate this out and G_SetRetryFlag() here instead? is just calling this from the menu 100% safe?
 	G_CheckDemoStatus(); // Cancel recording
 	if (modeattacking == ATTACKING_RECORD)
 		M_ChooseTimeAttack(0);
diff --git a/src/m_menu.h b/src/m_menu.h
index 9df56e8976..c1e48912ab 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -235,7 +235,7 @@ extern INT16 startmap;
 extern INT32 ultimate_selectable;
 extern INT16 char_on, startchar;
 
-#define MAXSAVEGAMES 31 //note: last save game is "no save"
+#define MAXSAVEGAMES 31
 #define NOSAVESLOT 0 //slot where Play Without Saving appears
 
 #define BwehHehHe() S_StartSound(NULL, sfx_bewar1+M_RandomKey(4)) // Bweh heh he
@@ -244,6 +244,8 @@ void M_ForceSaveSlotSelected(INT32 sslot);
 
 void M_CheatActivationResponder(INT32 ch);
 
+void M_ModeAttackRetry(INT32 choice);
+
 // Level select updating
 void Nextmap_OnChange(void);
 
diff --git a/src/p_setup.c b/src/p_setup.c
index a5544c26b7..11e6b4ef72 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2728,7 +2728,9 @@ boolean P_SetupLevel(boolean skipprecip)
 
 	// Special stage fade to white
 	// This is handled BEFORE sounds are stopped.
-	if (rendermode != render_none && G_IsSpecialStage(gamemap))
+	if (modeattacking && pausedelay == INT32_MIN)
+		ranspecialwipe = 2;
+	else if (rendermode != render_none && G_IsSpecialStage(gamemap))
 	{
 		tic_t starttime = I_GetTime();
 		tic_t endtime = starttime + (3*TICRATE)/2;
@@ -2778,6 +2780,12 @@ boolean P_SetupLevel(boolean skipprecip)
 		F_RunWipe(wipedefs[wipe_level_toblack], false);
 	}
 
+	if (ranspecialwipe == 2)
+	{
+		pausedelay = -NEWTICRATE;
+		S_StartSound(NULL, sfx_s3k73);
+	}
+
 	// Print "SPEEDING OFF TO [ZONE] [ACT 1]..."
 	if (!titlemapinaction && rendermode != render_none)
 	{
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 2a7e0636a3..6984115331 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -2367,11 +2367,13 @@ static void ST_overlayDrawer(void)
 		{
 			ST_drawFirstPersonHUD();
 			if (cv_powerupdisplay.value)
-				ST_drawPowerupHUD();
+				ST_drawPowerupHUD(); // same as it ever was...
 		}
 		else if (cv_powerupdisplay.value == 2)
-			ST_drawPowerupHUD();
+			ST_drawPowerupHUD(); // same as it ever was...
 	}
+	else if (!(netgame || multiplayer) && cv_powerupdisplay.value == 2)
+		ST_drawPowerupHUD(); // same as it ever was...
 
 #ifdef HAVE_BLUA
 	if (!(netgame || multiplayer) || !hu_showscores)
@@ -2393,7 +2395,7 @@ static void ST_overlayDrawer(void)
 	)
 		ST_drawTextHUD();
 
-	if (modeattacking && !hu_showscores)
+	if (modeattacking && !(demoplayback && hu_showscores))
 		ST_drawInput();
 
 	ST_drawDebugInfo();
-- 
GitLab