From d59f25a6cdd16fd1133c089bf6ba740dbc42e657 Mon Sep 17 00:00:00 2001
From: Sally Coolatta <tehrealsalt@gmail.com>
Date: Sun, 18 Apr 2021 12:59:49 -0400
Subject: [PATCH] stagefailed is more useful

- Can now apply to normal stages, simply defaults to "false" in normal stages.
- Post-level cutscenes are now always skipped when the stage was failed.
- Exposed the boolean as a Lua read+write global.

Desired for SUGOI, as it allows for visited flags not be updated, and level completion emblems to not be awarded. Which means a lot less crappy non-ideal workarounds.

Normal stage intermission currently does not reflect failure state at all. Maybe it could always skip, never award score bonuses, have different text... etc. Probably would leave that up to vanilla dev opinion.
---
 src/doomstat.h   |  2 +-
 src/g_game.c     | 15 +++++++++++----
 src/lua_script.c |  5 +++++
 src/p_setup.c    |  6 ++++--
 4 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/src/doomstat.h b/src/doomstat.h
index 2d28b81af7..2dbb144e64 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -496,7 +496,7 @@ extern UINT32 lastcustomtol;
 
 extern tic_t totalplaytime;
 
-extern UINT8 stagefailed;
+extern boolean stagefailed;
 
 // Emeralds stored as bits to throw savegame hackers off.
 extern UINT16 emeralds;
diff --git a/src/g_game.c b/src/g_game.c
index 2b304b4fdd..e6c445d68f 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -169,7 +169,7 @@ static boolean exitgame = false;
 static boolean retrying = false;
 static boolean retryingmodeattack = false;
 
-UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage.
+boolean stagefailed = false; // Used for GEMS BONUS? Also to see if you beat the stage.
 
 UINT16 emeralds;
 INT32 luabanks[NUM_LUABANKS];
@@ -3742,7 +3742,7 @@ static void G_UpdateVisited(void)
 	// Update visitation flags?
 	if ((!modifiedgame || savemoddata) // Not modified
 		&& !multiplayer && !demoplayback && (gametype == GT_COOP) // SP/RA/NiGHTS mode
-		&& !(spec && stagefailed)) // Not failed the special stage
+		&& !stagefailed) // Did not fail the stage
 	{
 		UINT8 earnedEmblems;
 
@@ -3963,7 +3963,7 @@ static void G_DoCompleted(void)
 	// If the current gametype has no intermission screen set, then don't start it.
 	Y_DetermineIntermissionType();
 
-	if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed) || (intertype == int_none))
+	if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none))
 	{
 		G_UpdateVisited();
 		G_HandleSaveLevel();
@@ -3994,8 +3994,15 @@ void G_AfterIntermission(void)
 
 	HU_ClearCEcho();
 
-	if ((gametyperules & GTR_CUTSCENES) && mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene.
+	if ((gametyperules & GTR_CUTSCENES) && mapheaderinfo[gamemap-1]->cutscenenum
+		&& !modeattacking
+		&& skipstats <= 1
+		&& (gamecomplete || !(marathonmode & MA_NOCUTSCENES))
+		&& stagefailed == false)
+	{
+		// Start a custom cutscene.
 		F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false);
+	}
 	else
 	{
 		if (nextmap < 1100-1)
diff --git a/src/lua_script.c b/src/lua_script.c
index 7fd5a98e6f..0a7e444225 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -380,6 +380,9 @@ int LUA_PushGlobals(lua_State *L, const char *word)
 	} else if (fastcmp(word, "gamestate")) {
 		lua_pushinteger(L, gamestate);
 		return 1;
+	} else if (fastcmp(word, "stagefailed")) {
+		lua_pushboolean(L, stagefailed);
+		return 1;
 	}
 	return 0;
 }
@@ -429,6 +432,8 @@ int LUA_CheckGlobals(lua_State *L, const char *word)
 	}
 	else if (fastcmp(word, "mapmusflags"))
 		mapmusflags = (UINT16)luaL_checkinteger(L, 2);
+	else if (fastcmp(word, "stagefailed"))
+		stagefailed = luaL_checkboolean(L, 2);
 	else
 		return 0;
 
diff --git a/src/p_setup.c b/src/p_setup.c
index 40dd1a2847..2e7db10551 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -3394,8 +3394,10 @@ static void P_InitLevelSettings(void)
 	numstarposts = 0;
 	ssspheres = timeinmap = 0;
 
-	// special stage
-	stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial
+	// Assume Special Stages were failed in unless proven otherwise - via P_GiveEmerald or emerald touchspecial
+	// Normal stages will default to be OK, unless a Lua script sets to false.
+	stagefailed = G_IsSpecialStage(gamemap);
+
 	// Reset temporary record data
 	memset(&ntemprecords, 0, sizeof(nightsdata_t));
 
-- 
GitLab