From 82b60cc5855c2e28a5d5afd59c4dc251da03cf76 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Jun 2023 20:27:38 +0100 Subject: [PATCH 1/8] Map types: Make more map ID types consistent as UINT16 - nextmap - prevmap - nextmapoverride - G_GetFirstMapOfGametype --- src/doomstat.h | 2 +- src/g_game.c | 10 +++++----- src/g_game.h | 4 ++-- src/menus/transient/level-select.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 619f01db3..c5b594e8d 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -343,7 +343,7 @@ struct textprompt_t extern textprompt_t *textprompts[MAX_PROMPTS]; // For the Custom Exit linedef. -extern INT16 nextmapoverride; +extern UINT16 nextmapoverride; extern UINT8 skipstats; // Fun extra stuff diff --git a/src/g_game.c b/src/g_game.c index f65f0ba6d..d940cbb46 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -183,7 +183,7 @@ boolean exitfadestarted = false; cutscene_t *cutscenes[128]; textprompt_t *textprompts[MAX_PROMPTS]; -INT16 nextmapoverride; +UINT16 nextmapoverride; UINT8 skipstats; // Pointers to each CTF flag @@ -332,7 +332,7 @@ typedef struct joystickvector2_s boolean precache = true; // if true, load all graphics at start -INT16 prevmap, nextmap; +UINT16 prevmap, nextmap; static void weaponPrefChange(void); static void weaponPrefChange2(void); @@ -3717,10 +3717,10 @@ UINT32 G_TOLFlag(INT32 pgametype) return 0; } -INT16 G_GetFirstMapOfGametype(UINT8 pgametype) +UINT16 G_GetFirstMapOfGametype(UINT8 pgametype) { UINT8 i = 0; - INT16 mapnum = NEXTMAP_INVALID; + UINT16 mapnum = NEXTMAP_INVALID; levelsearch_t templevelsearch; templevelsearch.cup = NULL; @@ -4181,7 +4181,7 @@ static void G_GetNextMap(void) // nextmap is 0-based, unlike gamemap if (nextmapoverride != 0) { - nextmap = (INT16)(nextmapoverride-1); + nextmap = (nextmapoverride-1); setalready = true; } else if (roundqueue.size > 0) diff --git a/src/g_game.h b/src/g_game.h index 2f498134e..34cfbd514 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -38,7 +38,7 @@ extern boolean playeringame[MAXPLAYERS]; extern tic_t levelstarttic; // for modding? -extern INT16 prevmap, nextmap; +extern UINT16 prevmap, nextmap; // see also G_MapNumber typedef enum @@ -276,7 +276,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics); // Don't split up TOL handling UINT32 G_TOLFlag(INT32 pgametype); -INT16 G_GetFirstMapOfGametype(UINT8 pgametype); +UINT16 G_GetFirstMapOfGametype(UINT8 pgametype); UINT16 G_RandMap(UINT32 tolflags, UINT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, UINT16 *extBuffer); void G_AddMapToBuffer(UINT16 map); diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index 2aeb50f55..68d395abf 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -131,7 +131,7 @@ UINT16 M_CountLevelsToShowInList(levelsearch_t *levelsearch) UINT16 M_GetFirstLevelInList(UINT8 *i, levelsearch_t *levelsearch) { - INT16 mapnum = NEXTMAP_INVALID; + UINT16 mapnum = NEXTMAP_INVALID; if (!levelsearch) return NEXTMAP_INVALID; From 0bec8317f3f59a6262c82909a5e012e0decdced9 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Jun 2023 20:51:48 +0100 Subject: [PATCH 2/8] Y_DetermineIntermissionType: Make this function the sole authority on whether an intermission occours or not. A return to cleanliness in G_DoCompleted. --- src/g_game.c | 4 +--- src/y_inter.c | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index d940cbb46..4c6ce067b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4520,9 +4520,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) - || (modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST)) - || (intertype == int_none)) + if (intertype == int_none) { G_UpdateVisited(); G_AfterIntermission(); diff --git a/src/y_inter.c b/src/y_inter.c index 70ae5e7fb..0d276928f 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1589,7 +1589,11 @@ void Y_Ticker(void) void Y_DetermineIntermissionType(void) { // no intermission for GP events - if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE) + if ((grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE) + // or for failing in time attack mode + || (modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST)) + // or for explicit requested skip (outside of modeattacking) + || (modeattacking == ATTACKING_NONE && skipstats != 0)) { intertype = int_none; return; From f91f075a0da0f2b3ec57dd4f148db474023eafc5 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Jun 2023 20:54:21 +0100 Subject: [PATCH 3/8] ACS: void MapWarp(str mapname, bool showintermission) An immediate level change on command, to the specified level (via string). Utilises the existing nextmapoverride and skipstats system, but with skipstats assumed to be the default. --- src/acs/call-funcs.cpp | 58 +++++++++++++++++++++++++++++++++++++++++ src/acs/call-funcs.hpp | 2 ++ src/acs/environment.cpp | 1 + 3 files changed, 61 insertions(+) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index c5e07f025..cfb84c7b8 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -1652,6 +1652,64 @@ bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, return false; } +/*-------------------------------------------------- + bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Immediately warps to another level. +--------------------------------------------------*/ + +bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = NULL; + + ACSVM::String *str = nullptr; + + const char *levelName = NULL; + size_t levelLen = 0; + + UINT16 nextmap = NEXTMAP_INVALID; + + (void)argC; + + if (exitcountdown == 1) + { + // An exit is already in progress. + return false; + } + + map = thread->scopeMap; + + str = map->getString(argV[0]); + + levelName = str->str; + levelLen = str->len; + + if (!levelLen || !levelName) + { + CONS_Alert(CONS_WARNING, "MapWarp level name was not provided.\n"); + } + + nextmap = G_MapNumber(levelName); + + if (nextmap == NEXTMAP_INVALID) + { + CONS_Alert(CONS_WARNING, "MapWarp level %s is not valid or loaded.\n", levelName); + return false; + } + + nextmapoverride = (nextmap + 1); + + if (argV[1] == 0) + skipstats = 1; + + exitcountdown = 1; + + if (server) + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + + return false; +} + /*-------------------------------------------------- bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index e2c43e945..a59b4d916 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -83,6 +83,8 @@ bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); + bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index e90c34cb6..a3adaa50f 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -165,6 +165,7 @@ Environment::Environment() addFuncDataACS0( 501, addCallFunc(CallFunc_PodiumPosition)); addFuncDataACS0( 502, addCallFunc(CallFunc_PodiumFinish)); addFuncDataACS0( 503, addCallFunc(CallFunc_SetLineRenderStyle)); + addFuncDataACS0( 504, addCallFunc(CallFunc_MapWarp)); } ACSVM::Thread *Environment::allocThread() From d75ebd54537fca6be7c87caf23ffd41a05ee3d21 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Jun 2023 20:56:49 +0100 Subject: [PATCH 4/8] If a nextmapoverride is used in GP, do not take a life and restart the level when exiting without having properly won. It may be some sort of secret. --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 4c6ce067b..a019483d7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3303,7 +3303,7 @@ void G_ExitLevel(void) } } - if (!G_GametypeUsesLives()) + if (!G_GametypeUsesLives() || nextmapoverride != 0) ; // never force a retry else if (specialstageinfo.valid == true || (gametyperules & GTR_BOSS)) { From f8dd63609a6dacf81b0dfccf1af2a1ba3b94cd31 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Jun 2023 21:07:55 +0100 Subject: [PATCH 5/8] On second thoughts, tie the never-force-a-retry onto skipstats, which is for direct warps. We probably want to force retries for poor performance if intermission is relevant. --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index a019483d7..16f999ac9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3303,7 +3303,7 @@ void G_ExitLevel(void) } } - if (!G_GametypeUsesLives() || nextmapoverride != 0) + if (!G_GametypeUsesLives() || skipstats != 0) ; // never force a retry else if (specialstageinfo.valid == true || (gametyperules & GTR_BOSS)) { From a2902ab1ff7cb921a8b3bab37c4f61ce49d3452a Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 00:51:51 +0100 Subject: [PATCH 6/8] Use to-white fade when entering a map via skipstats --- src/p_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index ea1185a67..d124d3c97 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8095,7 +8095,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) levelfadecol = 0; wipetype = wipe_encore_towhite; } - else if (encoremode) + else if (encoremode || (skipstats == 1)) { levelfadecol = 0; wipetype = wipe_encore_towhite; From deca3cb91116ef678362913e358224ed15d009ba Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 20:40:01 +0100 Subject: [PATCH 7/8] Add mid-fade warp sound per suggestion --- src/p_setup.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index d124d3c97..234c98e13 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8095,7 +8095,14 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) levelfadecol = 0; wipetype = wipe_encore_towhite; } - else if (encoremode || (skipstats == 1)) + else if (skipstats == 1) + { + if (ranspecialwipe != 2) + S_StartSound(NULL, sfx_s3k73); + levelfadecol = 0; + wipetype = wipe_encore_towhite; + } + else if (encoremode) { levelfadecol = 0; wipetype = wipe_encore_towhite; From a682c4a9ad6e94c344ce4305b83c48d51dc9da11 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Jun 2023 20:55:00 +0100 Subject: [PATCH 8/8] Add sfx_endwrp Dummy sound to be implemented later for the end of a skipstats warp, but the thok actually sounds kind of fun. Requires skipstats (and nextmapoverride, for cleanliness) to be unset in P_PostLoadLevel instead of P_LoadLevel. --- src/k_kart.c | 4 ++++ src/p_setup.c | 6 +++--- src/sounds.c | 1 + src/sounds.h | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 90a7bd9ba..d47d63390 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -146,6 +146,10 @@ void K_TimerInit(void) P_InstaThrust(player->mo, player->mo->angle, K_GetKartSpeed(player, false, false)); } } + else if (skipstats != 0) + { + S_StartSound(NULL, sfx_endwrp); + } if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) == (GTR_CATCHER|GTR_CIRCUIT)) { diff --git a/src/p_setup.c b/src/p_setup.c index 234c98e13..aa52bc5c5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8308,9 +8308,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (precache || dedicated) R_PrecacheLevel(); - nextmapoverride = 0; - skipstats = 0; - if (!demo.playback) { mapheaderinfo[gamemap-1]->records.mapvisited |= MV_VISITED; @@ -8387,6 +8384,9 @@ void P_PostLoadLevel(void) { K_TimerInit(); + nextmapoverride = 0; + skipstats = 0; + P_RunCachedActions(); if (marathonmode & MA_INGAME) diff --git a/src/sounds.c b/src/sounds.c index d8852928b..85b111a50 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1102,6 +1102,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"typri2", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SA2 final boss-type typewriting {"eggspr", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Sonic Unleashed Trap Spring {"achiev", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Achievement"}, + {"endwrp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // End of a "Tutorial Teleport" // SRB2Kart - Drop target sounds {"kdtrg1", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Low energy, SF_X8AWAYSOUND diff --git a/src/sounds.h b/src/sounds.h index 422138d65..a2f786030 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1169,6 +1169,7 @@ typedef enum sfx_typri2, sfx_eggspr, sfx_achiev, + sfx_endwrp, // SRB2Kart - Drop target sounds sfx_kdtrg1,