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!
This commit is contained in:
toaster 2023-03-13 16:44:21 +00:00
parent 1d3b5adfdf
commit 1701662b6b
3 changed files with 87 additions and 32 deletions

View file

@ -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);

View file

@ -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)<<FRACBITS, FRACUNIT, 0, patch, colormap);
if (M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID)
if (templevelsearch.cup == &dummy_lostandfound)
; // Only ever placed on the list if valid
else if (M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID)
{
patch_t *st = W_CachePatchName(va("ICONST0%d", (cupgrid.previewanim % 4) + 1), PU_CACHE);
V_DrawScaledPatch(x + 8, y + icony, 0, st);

View file

@ -9,6 +9,8 @@
#include "../../f_finale.h" // F_WipeStartScreen
#include "../../v_video.h"
cupheader_t dummy_lostandfound;
menuitem_t PLAY_LevelSelect[] =
{
{IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, {.routine = M_LevelSelectHandler}, 0, 0},
@ -71,10 +73,14 @@ boolean M_CanShowLevelInList(INT16 mapnum, levelsearch_t *levelsearch)
return false;
// Don't permit cup when no cup requested (also no dupes in time attack)
if (levelsearch->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;