From 1701662b6be6439d401023ead5a375919b85f9ed Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 13 Mar 2023 16:44:21 +0000 Subject: [PATCH] Lost and Found - When selecting levels: - If the gametype uses cups - and a map has no cup - and you're not in Grand Prix mode - show those maps in a quasi-cup called "Lost and Found". - Implementation details: - a few == checks for the pointer to `cupheader_t dummy_lostandfound` - Otherwise most of the apparatus was built as part of prior art! --- src/k_menu.h | 2 + src/k_menudraw.c | 16 ++++- src/menus/transient/level-select.c | 101 ++++++++++++++++++++--------- 3 files changed, 87 insertions(+), 32 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index cb7e79a10..8fbaed1bf 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -743,6 +743,8 @@ extern struct levellist_s { boolean netgame; // Start the game in an actual server } levellist; +extern cupheader_t dummy_lostandfound; + boolean M_CanShowLevelInList(INT16 mapnum, levelsearch_t *levelsearch); UINT16 M_CountLevelsToShowInList(levelsearch_t *levelsearch); UINT16 M_GetFirstLevelInList(UINT8 *i, levelsearch_t *levelsearch); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 01089958e..94a390e62 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2092,7 +2092,11 @@ static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch) V_DrawScaledPatch(0, y, 0, W_CachePatchName("MENUHINT", PU_CACHE)); - if (levelsearch->cup) + if (levelsearch->cup == &dummy_lostandfound) + { + V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, y+6, 0, "Lost and Found"); + } + else if (levelsearch->cup) { boolean unlocked = (M_GetFirstLevelInList(&temp, levelsearch) != NEXTMAP_INVALID); UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GREY, GTC_MENUCACHE); @@ -2176,6 +2180,12 @@ void M_DrawCupSelect(void) colormap = NULL; } + if (templevelsearch.cup == &dummy_lostandfound) + { + // No cup? Lost and found! + monitor = '0'; + } + else { if (templevelsearch.cup->monitor < 10) { @@ -2200,7 +2210,9 @@ void M_DrawCupSelect(void) V_DrawFixedPatch((x)*FRACUNIT, (y)<cupmode - && (levelsearch->timeattack || !levelsearch->cup) - && mapheaderinfo[mapnum]->cup != levelsearch->cup) - return false; + if (levelsearch->cupmode) + { + cupheader_t *cup = (levelsearch->cup == &dummy_lostandfound) ? NULL : levelsearch->cup; + + if ((!cup || levelsearch->timeattack) + && mapheaderinfo[mapnum]->cup != cup) + return false; + } // Finally, the most complex check: does the map have lock conditions? if (levelsearch->checklocked) @@ -100,7 +106,7 @@ UINT16 M_CountLevelsToShowInList(levelsearch_t *levelsearch) if (!levelsearch) return 0; - if (levelsearch->cup) + if (levelsearch->cup && levelsearch->cup != &dummy_lostandfound) { if (levelsearch->checklocked && M_CupLocked(levelsearch->cup)) return 0; @@ -129,7 +135,7 @@ UINT16 M_GetFirstLevelInList(UINT8 *i, levelsearch_t *levelsearch) if (!levelsearch) return NEXTMAP_INVALID; - if (levelsearch->cup) + if (levelsearch->cup && levelsearch->cup != &dummy_lostandfound) { if (levelsearch->checklocked && M_CupLocked(levelsearch->cup)) { @@ -165,7 +171,7 @@ UINT16 M_GetNextLevelInList(UINT16 mapnum, UINT8 *i, levelsearch_t *levelsearch) if (!levelsearch) return NEXTMAP_INVALID; - if (levelsearch->cup) + if (levelsearch->cup && levelsearch->cup != &dummy_lostandfound) { mapnum = NEXTMAP_INVALID; (*i)++; @@ -213,6 +219,9 @@ boolean M_LevelListFromGametype(INT16 gt) { cupgrid.cappages = 0; cupgrid.builtgrid = NULL; + dummy_lostandfound.cachedlevels[0] = NEXTMAP_INVALID; + + first = false; } levellist.newgametype = gt; @@ -232,8 +241,6 @@ boolean M_LevelListFromGametype(INT16 gt) levellist.levelsearch.cupmode = (!(gametypes[gt]->rules & GTR_NOCUPSELECT)); CV_SetValue(&cv_dummyspbattack, 0); - - first = false; } // Obviously go to Cup Select in gametypes that have cups. @@ -269,6 +276,31 @@ boolean M_LevelListFromGametype(INT16 gt) } memset(cupgrid.builtgrid, 0, cupgrid.cappages * pagelen); + // The following doubles the size of the buffer if necessary. +#define GRID_INSERTCUP \ + if ((currentid * sizeof(cupheader_t*)) >= cupgrid.cappages * pagelen) \ + { \ + const size_t firstlen = cupgrid.cappages * pagelen; \ + cupgrid.builtgrid = Z_Realloc(cupgrid.builtgrid, \ + firstlen * 2, \ + PU_STATIC, NULL); \ + \ + if (!cupgrid.builtgrid) \ + { \ + I_Error("M_LevelListFromGametype: Not enough memory to reallocate builtgrid"); \ + } \ + \ + cupgrid.cappages *= 2; \ + } \ + \ + cupgrid.builtgrid[currentid] = templevelsearch.cup; + +#define GRID_FOCUSCUP \ + cupgrid.x = currentid % CUPMENU_COLUMNS; \ + cupgrid.y = (currentid / CUPMENU_COLUMNS) % CUPMENU_ROWS; \ + cupgrid.pageno = currentid / (CUPMENU_COLUMNS * CUPMENU_ROWS); \ + currentvalid = true; + while (templevelsearch.cup) { templevelsearch.checklocked = false; @@ -281,23 +313,7 @@ boolean M_LevelListFromGametype(INT16 gt) foundany = true; - if ((currentid * sizeof(cupheader_t*)) >= cupgrid.cappages * pagelen) - { - // Double the size of the buffer, and clear the other stuff. - const size_t firstlen = cupgrid.cappages * pagelen; - cupgrid.builtgrid = Z_Realloc(cupgrid.builtgrid, - firstlen * 2, - PU_STATIC, NULL); - - if (!cupgrid.builtgrid) - { - I_Error("M_LevelListFromGametype: Not enough memory to reallocate builtgrid"); - } - - cupgrid.cappages *= 2; - } - - cupgrid.builtgrid[currentid] = templevelsearch.cup; + GRID_INSERTCUP; templevelsearch.checklocked = true; if (M_GetFirstLevelInList(&temp, &templevelsearch) != NEXTMAP_INVALID) @@ -308,10 +324,7 @@ boolean M_LevelListFromGametype(INT16 gt) ? (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == templevelsearch.cup) : (gt == -1 && levellist.levelsearch.cup == templevelsearch.cup)) { - cupgrid.x = currentid % CUPMENU_COLUMNS; - cupgrid.y = (currentid / CUPMENU_COLUMNS) % CUPMENU_ROWS; - cupgrid.pageno = currentid / (CUPMENU_COLUMNS * CUPMENU_ROWS); - currentvalid = true; + GRID_FOCUSCUP; } } @@ -319,6 +332,34 @@ boolean M_LevelListFromGametype(INT16 gt) templevelsearch.cup = templevelsearch.cup->next; } + // Lost and found, a simplified version of the above loop. + if (cupgrid.grandprix == false) + { + templevelsearch.cup = &dummy_lostandfound; + templevelsearch.checklocked = true; + + if (M_GetFirstLevelInList(&temp, &levellist.levelsearch) != NEXTMAP_INVALID) + { + foundany = true; + GRID_INSERTCUP; + highestunlockedid = currentid; + + if (Playing() + ? (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == NULL) + : (gt == -1 && levellist.levelsearch.cup == templevelsearch.cup)) + { + GRID_FOCUSCUP; + } + + currentid++; + } + + templevelsearch.cup = NULL; + } + +#undef GRID_INSERTCUP +#undef GRID_FOCUSCUP + if (foundany == false) { return false;