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
This commit is contained in:
Fabian Greffrath 2025-05-08 07:06:04 +02:00 committed by GitHub
parent 7bc3712cfd
commit 232c1e478f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 86 additions and 17 deletions

View File

@ -1076,12 +1076,12 @@ int G_GotoNextLevel(int *pEpi, int *pMap)
{12, 13, 19, 15, 16, 17, 18, 21, 14}, {12, 13, 19, 15, 16, 17, 18, 21, 14},
{22, 23, 24, 25, 29, 27, 28, 31, 26}, {22, 23, 24, 25, 29, 27, 28, 31, 26},
{32, 33, 34, 35, 36, 39, 38, 41, 37}, {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] = { byte doom2_next[32] = {
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 31, 17, 18, 19, 20, 21, 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 32, 16
}; };
@ -1096,25 +1096,19 @@ int G_GotoNextLevel(int *pEpi, int *pMap)
next = gamemapinfo->nextsecret; next = gamemapinfo->nextsecret;
else if (gamemapinfo->nextmap[0]) else if (gamemapinfo->nextmap[0])
next = gamemapinfo->nextmap; next = gamemapinfo->nextmap;
else if (gamemapinfo->flags & MapInfo_EndGame)
{
epsd = 1;
map = 1;
}
if (next) if (next)
G_ValidateMapName(next, &epsd, &map); G_ValidateMapName(next, &epsd, &map);
} }
else
if (map == -1)
{ {
// secret level // secret level
doom2_next[14] = (haswolflevels ? 31 : 16); doom2_next[14] = (haswolflevels ? 31 : 16);
// shareware doom has only episode 1 // 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 //doom2_next and doom_next are 0 based, unlike gameepisode and gamemap
epsd = gameepisode - 1; epsd = gameepisode - 1;
@ -1159,8 +1153,11 @@ int G_GotoNextLevel(int *pEpi, int *pMap)
{ {
char *name = MapName(epsd, map); char *name = MapName(epsd, map);
if (W_CheckNumForName(name) == -1) if (map == -1 || W_CheckNumForName(name) == -1)
displaymsg("Next level not found: %s", name); {
name = MapName(gameepisode, gamemap);
displaymsg("Next level not found for %s", name);
}
else else
{ {
G_DeferedInitNew(gameskill, epsd, map); G_DeferedInitNew(gameskill, epsd, map);
@ -1171,6 +1168,66 @@ int G_GotoNextLevel(int *pEpi, int *pMap)
return false; 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 G_StrictModeSkipEvent(event_t *ev)
{ {
static boolean enable_mouse = false; static boolean enable_mouse = false;

View File

@ -82,6 +82,7 @@ demo_version_t G_GetNamedComplevel(const char *arg);
const char *G_GetCurrentComplevelName(void); const char *G_GetCurrentComplevelName(void);
int G_GotoNextLevel(int *pEpi, int *pMap); int G_GotoNextLevel(int *pEpi, int *pMap);
int G_GotoPrevLevel(void);
void G_BindGameInputVariables(void); void G_BindGameInputVariables(void);
void G_BindGameVariables(void); void G_BindGameVariables(void);

View File

@ -702,6 +702,7 @@ void M_BindInputVariables(void)
BIND_INPUT(input_menu_reloadlevel, "Restart current level/demo"); BIND_INPUT(input_menu_reloadlevel, "Restart current level/demo");
BIND_INPUT(input_menu_nextlevel, "Go to next level"); 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"); BIND_INPUT(input_hud_timestats, "Toggle display of level stats and time");

View File

@ -68,6 +68,7 @@ enum
input_menu_clear, input_menu_clear,
input_menu_reloadlevel, input_menu_reloadlevel,
input_menu_nextlevel, input_menu_nextlevel,
input_menu_prevlevel,
input_hud_timestats, input_hud_timestats,

View File

@ -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 (M_InputActivated(input_demo_fforward))
{ {
if (demoplayback && !PLAYBACK_SKIP && !fastdemo && !D_CheckNetConnect()) if (demoplayback && !PLAYBACK_SKIP && !fastdemo && !D_CheckNetConnect())

View File

@ -1418,6 +1418,7 @@ static setup_menu_t keys_settings3[] = {
// [FG] reload current level / go to next level // [FG] reload current level / go to next level
{"Reload Map/Demo", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_menu_reloadlevel}, {"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}, {"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}, {"Show Stats/Time", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_hud_timestats},
MI_GAP, MI_GAP,
{"Fast-FWD Demo", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_demo_fforward}, {"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}, {"Default Speed", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_speed_default},
MI_GAP, MI_GAP,
{"Begin Chat", S_INPUT, KB_X, M_SPC, {0}, m_scrn, input_chat}, {"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 MI_END
}; };