From 232c1e478fd07a0b7e2fcbfcaa97d9955f51321b Mon Sep 17 00:00:00 2001 From: Fabian Greffrath Date: Thu, 8 May 2025 07:06:04 +0200 Subject: [PATCH] add a "prev map" key binding (#2046) * add a "prev map" key binding Fixes #2007 * simplify * add safety measures * simplify again * fix * simplify logic * add to key binding menu instead of player specific chat keys * start with gamemap 99 when crossing gameepisodes * start new episode with gamemap = cur_map to allow a full gamemap circle * fix UMAPINFO * reset gamemap outside the while() condition * do not let linear and UMAPINFO maps cross * prevent G_GotoNextLevel() from cycling across levels that end the game * check either UMAPINFO or linear progression in G_GotoNextLevel() * don't report the map we couldn't find, but the map that we couldn't find a previous map for --- src/g_game.c | 83 ++++++++++++++++++++++++++++++++++++++++++-------- src/g_game.h | 1 + src/m_input.c | 1 + src/m_input.h | 1 + src/mn_menu.c | 12 ++++++++ src/mn_setup.c | 5 +-- 6 files changed, 86 insertions(+), 17 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index cbad5cab..b4dd7b4b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1076,12 +1076,12 @@ int G_GotoNextLevel(int *pEpi, int *pMap) {12, 13, 19, 15, 16, 17, 18, 21, 14}, {22, 23, 24, 25, 29, 27, 28, 31, 26}, {32, 33, 34, 35, 36, 39, 38, 41, 37}, - {42, 49, 44, 45, 46, 47, 48, 11, 43} + {42, 49, 44, 45, 46, 47, 48, -1, 43} }; byte doom2_next[32] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, + 22, 23, 24, 25, 26, 27, 28, 29, 30, -1, 32, 16 }; @@ -1096,25 +1096,19 @@ int G_GotoNextLevel(int *pEpi, int *pMap) next = gamemapinfo->nextsecret; else if (gamemapinfo->nextmap[0]) next = gamemapinfo->nextmap; - else if (gamemapinfo->flags & MapInfo_EndGame) - { - epsd = 1; - map = 1; - } if (next) G_ValidateMapName(next, &epsd, &map); } - - if (map == -1) + else { // secret level doom2_next[14] = (haswolflevels ? 31 : 16); // shareware doom has only episode 1 - doom_next[0][7] = (gamemode == shareware ? 11 : 21); + doom_next[0][7] = (gamemode == shareware ? -1 : 21); - doom_next[2][7] = (gamemode == registered ? 11 : 41); + doom_next[2][7] = (gamemode == registered ? -1 : 41); //doom2_next and doom_next are 0 based, unlike gameepisode and gamemap epsd = gameepisode - 1; @@ -1159,8 +1153,11 @@ int G_GotoNextLevel(int *pEpi, int *pMap) { char *name = MapName(epsd, map); - if (W_CheckNumForName(name) == -1) - displaymsg("Next level not found: %s", name); + if (map == -1 || W_CheckNumForName(name) == -1) + { + name = MapName(gameepisode, gamemap); + displaymsg("Next level not found for %s", name); + } else { G_DeferedInitNew(gameskill, epsd, map); @@ -1171,6 +1168,66 @@ int G_GotoNextLevel(int *pEpi, int *pMap) return false; } +int G_GotoPrevLevel(void) +{ + if (gamestate != GS_LEVEL || deathmatch || netgame || demorecording + || demoplayback || menuactive) + { + return false; + } + + const int cur_epsd = gameepisode; + const int cur_map = gamemap; + struct mapentry_s *const cur_gamemapinfo = gamemapinfo; + int ret = false; + + do + { + gamemap = cur_map; + + while ((gamemap = (gamemap + 99) % 100) != cur_map) + { + int next_epsd, next_map; + gamemapinfo = G_LookupMapinfo(gameepisode, gamemap); + G_GotoNextLevel(&next_epsd, &next_map); + + // do not let linear and UMAPINFO maps cross + if ((cur_gamemapinfo == NULL && gamemapinfo != NULL) || + (cur_gamemapinfo != NULL && gamemapinfo == NULL)) + { + continue; + } + + if (next_epsd == cur_epsd && next_map == cur_map) + { + char *name = MapName(gameepisode, gamemap); + + if (W_CheckNumForName(name) != -1) + { + G_DeferedInitNew(gameskill, gameepisode, gamemap); + ret = true; + break; + } + } + } + } while (ret == false + // only check one episode in Doom 2 + && gamemode != commercial + && (gameepisode = (gameepisode + 9) % 10) != cur_epsd); + + gameepisode = cur_epsd; + gamemap = cur_map; + gamemapinfo = cur_gamemapinfo; + + if (ret == false) + { + char *name = MapName(gameepisode, gamemap); + displaymsg("Previous level not found for %s", name); + } + + return ret; +} + static boolean G_StrictModeSkipEvent(event_t *ev) { static boolean enable_mouse = false; diff --git a/src/g_game.h b/src/g_game.h index 89636719..60ca3d79 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -82,6 +82,7 @@ demo_version_t G_GetNamedComplevel(const char *arg); const char *G_GetCurrentComplevelName(void); int G_GotoNextLevel(int *pEpi, int *pMap); +int G_GotoPrevLevel(void); void G_BindGameInputVariables(void); void G_BindGameVariables(void); diff --git a/src/m_input.c b/src/m_input.c index f5e44982..8a1ab1a9 100644 --- a/src/m_input.c +++ b/src/m_input.c @@ -702,6 +702,7 @@ void M_BindInputVariables(void) BIND_INPUT(input_menu_reloadlevel, "Restart current level/demo"); BIND_INPUT(input_menu_nextlevel, "Go to next level"); + BIND_INPUT(input_menu_prevlevel, "Go to previous level"); BIND_INPUT(input_hud_timestats, "Toggle display of level stats and time"); diff --git a/src/m_input.h b/src/m_input.h index c135ce1b..265a8e49 100644 --- a/src/m_input.h +++ b/src/m_input.h @@ -68,6 +68,7 @@ enum input_menu_clear, input_menu_reloadlevel, input_menu_nextlevel, + input_menu_prevlevel, input_hud_timestats, diff --git a/src/mn_menu.c b/src/mn_menu.c index 3ab9c033..dc1f51b2 100644 --- a/src/mn_menu.c +++ b/src/mn_menu.c @@ -2627,6 +2627,18 @@ boolean M_ShortcutResponder(const event_t *ev) } } + if (M_InputActivated(input_menu_prevlevel)) + { + if (demoplayback && singledemo && !PLAYBACK_SKIP) + { + return false; + } + else if (G_GotoPrevLevel()) + { + return true; + } + } + if (M_InputActivated(input_demo_fforward)) { if (demoplayback && !PLAYBACK_SKIP && !fastdemo && !D_CheckNetConnect()) diff --git a/src/mn_setup.c b/src/mn_setup.c index 66188bf1..66cf4768 100644 --- a/src/mn_setup.c +++ b/src/mn_setup.c @@ -1418,6 +1418,7 @@ static setup_menu_t keys_settings3[] = { // [FG] reload current level / go to next level {"Reload Map/Demo", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_menu_reloadlevel}, {"Next Map", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_menu_nextlevel}, + {"Previous Map", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_menu_prevlevel}, {"Show Stats/Time", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_hud_timestats}, MI_GAP, {"Fast-FWD Demo", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_demo_fforward}, @@ -1428,10 +1429,6 @@ static setup_menu_t keys_settings3[] = { {"Default Speed", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_speed_default}, MI_GAP, {"Begin Chat", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_chat}, - {"Player 1", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_chat_dest0}, - {"Player 2", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_chat_dest1}, - {"Player 3", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_chat_dest2}, - {"Player 4", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_chat_dest3}, MI_END };