Merge branch 'locked-cuprow' into 'master'

Second row of cups is invisible if none of them are unlocked

See merge request KartKrew/Kart!1652
This commit is contained in:
Oni 2023-11-22 07:30:36 +00:00
commit 25d10e382a
13 changed files with 372 additions and 63 deletions

View file

@ -1609,6 +1609,7 @@ void D_SRB2Main(void)
//
P_InitMapData();
basenummapheaders = nummapheaders;
basenumkartcupheaders = numkartcupheaders;
CON_SetLoadingProgress(LOADED_IWAD);

View file

@ -2464,6 +2464,20 @@ void readunlockable(MYFILE *f, INT32 num)
Z_Free(s);
}
// Todo: Own func
static cupheader_t *SOChelper_cupbyname(char *name)
{
cupheader_t *cup = kartcupheaders;
UINT32 hash = quickncasehash(name, MAXCUPNAME);
while (cup)
{
if (hash == cup->namehash && !strcmp(cup->name, name))
return cup;
cup = cup->next;
}
return NULL;
}
// This is a home-grown strtok(" ") equivalent so we can isolate the first chunk without destroying the rest of the line.
static void conditiongetparam(char **params, UINT8 paramid, char **spos)
{
@ -2690,6 +2704,63 @@ static void readcondition(UINT16 set, UINT32 id, char *word2)
re = -1;
x1 = atoi(params[2]);
}
else if (fastcmp(params[0], "ALLCUPRECORDS"))
{
ty = UC_ALLCUPRECORDS;
re = -1;
x1 = 0;
x2 = KARTSPEED_EASY;
if (params[1])
{
if (!fastcmp(params[1], "ALL"))
{
cupheader_t *cup = SOChelper_cupbyname(params[1]);
if (!cup)
{
deh_warning("Invalid cup %s for condition ID %d", params[1], id+1);
return;
}
re = cup->id;
}
if (params[2])
{
if (!fastcmp(params[1], "ANY"))
{
if ((offset=0) || fastcmp(params[2], "GOLD")
|| (++offset && fastcmp(params[2], "SILVER"))
|| (++offset && fastcmp(params[2], "BRONZE")))
{
x1 = offset + 1;
}
else
{
deh_warning("placement requirement \"%s\" invalid for condition ID %d", params[2], id+1);
return;
}
}
if (params[3])
{
if (fastcmp(params[3], "NORMAL"))
x2 = KARTSPEED_NORMAL;
else if (fastcmp(params[3], "HARD"))
x2 = KARTSPEED_HARD;
else if (fastcmp(params[3], "MASTER"))
x2 = KARTGP_MASTER;
else
{
deh_warning("gamespeed requirement \"%s\" invalid for condition ID %d", params[3], id+1);
return;
}
}
}
}
}
else if ((offset=0) || fastcmp(params[0], "ALLCHAOS")
|| (++offset && fastcmp(params[0], "ALLSUPER"))
|| (++offset && fastcmp(params[0], "ALLEMERALDS")))
@ -2907,14 +2978,7 @@ static void readcondition(UINT16 set, UINT32 id, char *word2)
re = -1;
if (!fastcmp(params[1], "ANY"))
{
cupheader_t *cup = kartcupheaders;
UINT32 hash = quickncasehash(params[1], MAXCUPNAME);
while (cup)
{
if (hash == cup->namehash && !strcmp(cup->name, params[1]))
break;
cup = cup->next;
}
cupheader_t *cup = SOChelper_cupbyname(params[1]);
if (!cup)
{

View file

@ -489,13 +489,18 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
if (!cup)
{
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
cup->monitor = 1;
cup->cache_cuplock = MAXUNLOCKABLES;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
cup->namehash = hash;
// Handle some variable init.
cup->monitor = 1;
cup->id = numkartcupheaders;
cup->cache_cuplock = MAXUNLOCKABLES;
for (i = 0; i < CUPCACHE_MAX; i++)
cup->cachedlevels[i] = NEXTMAP_INVALID;
char *start = strchr(word2, '_');
if (start)
start++;
@ -608,6 +613,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
if (gamedataadded)
{
basenummapheaders = nummapheaders;
basenumkartcupheaders = numkartcupheaders;
G_LoadGameData();
}

View file

@ -57,6 +57,9 @@ extern UINT32 maptol;
extern INT32 cursaveslot;
extern UINT8 gamecomplete;
#define CUPMENU_COLUMNS 7
#define CUPMENU_ROWS 2
// Extra abilities/settings for skins (combinable stuff)
typedef enum
{
@ -424,7 +427,7 @@ struct cupheader_t
};
extern cupheader_t *kartcupheaders; // Start of cup linked list
extern UINT16 numkartcupheaders;
extern UINT16 numkartcupheaders, basenumkartcupheaders;
struct unloaded_cupheader_t
{

View file

@ -204,6 +204,7 @@ unloaded_mapheader_t *unloadedmapheaders = NULL;
// Kart cup definitions
cupheader_t *kartcupheaders = NULL;
UINT16 numkartcupheaders = 0;
UINT16 basenumkartcupheaders = 0;
unloaded_cupheader_t *unloadedcupheaders = NULL;

View file

@ -752,8 +752,6 @@ void M_SetupPlayMenu(INT32 choice);
void M_SetupGametypeMenu(INT32 choice);
void M_SetupRaceMenu(INT32 choice);
#define CUPMENU_COLUMNS 7
#define CUPMENU_ROWS 2
#define CUPMENU_CURSORID (cupgrid.x + (cupgrid.y * CUPMENU_COLUMNS) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS)))
extern struct cupgrid_s {
@ -764,6 +762,7 @@ extern struct cupgrid_s {
size_t cappages;
tic_t previewanim;
boolean grandprix; // Setup grand prix server after picking
boolean cache_secondrowlocked;
} cupgrid;
typedef struct levelsearch_s {
@ -1274,6 +1273,8 @@ extern struct challengesmenu_s {
UINT16 unlockcount[CMC_MAX];
UINT8 fade;
boolean cache_secondrowlocked;
} challengesmenu;
menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu);

View file

@ -2712,7 +2712,9 @@ void M_DrawCupSelect(void)
for (i = 0; i < CUPMENU_COLUMNS; i++)
{
for (j = 0; j < CUPMENU_ROWS; j++)
x = 14 + (i*42);
for (j = 0; j < (cupgrid.cache_secondrowlocked ? 1 : CUPMENU_ROWS); j++)
{
size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
@ -2721,8 +2723,9 @@ void M_DrawCupSelect(void)
templevelsearch.cup = cupgrid.builtgrid[id];
x = 14 + (i*42);
y = 20 + (j*44) - (30*menutransition.tics);
if (cupgrid.cache_secondrowlocked == true)
y += 28;
const boolean isGP = (cupgrid.grandprix && (cv_dummygpdifficulty.value >= 0 && cv_dummygpdifficulty.value < KARTGP_MAX));
if (isGP)
@ -2745,11 +2748,23 @@ void M_DrawCupSelect(void)
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP1", PU_CACHE));
}
// used to be 8 + (j*100) - (30*menutransition.tics)
// but one-row mode means y has to be changed
// this is the difference between y and that
if (j == 0)
{
y -= 12; // (8) - (20)
}
else
{
y += 44; //(8 + 100) - (20 + 44)
}
if (windata && windata->best_placement != 0)
{
M_DrawCupWinData(
x,
8 + (j*100) - (30*menutransition.tics),
y,
templevelsearch.cup,
cv_dummygpdifficulty.value,
(cupgrid.previewanim & 1),
@ -2761,6 +2776,8 @@ void M_DrawCupSelect(void)
x = 14 + (cupgrid.x*42);
y = 20 + (cupgrid.y*44) - (30*menutransition.tics);
if (cupgrid.cache_secondrowlocked == true)
y += 28;
V_DrawScaledPatch(x - 4, y - 1, 0, W_CachePatchName("CUPCURS", PU_CACHE));
@ -5670,40 +5687,56 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
M_DrawCupPreview(146, &templevelsearch);
maxid = id = (temp->id % 14);
maxid = id = (temp->id % (CUPMENU_COLUMNS * CUPMENU_ROWS));
offset = (temp->id - id) * 2;
while (temp && maxid < 14)
while (temp && maxid < (CUPMENU_COLUMNS * CUPMENU_ROWS))
{
maxid++;
temp = temp->next;
}
V_DrawFadeFill(4, (BASEVIDHEIGHT-(4+16)), 28 + offset, 16, 0, 31, challengetransparentstrength);
y = (BASEVIDHEIGHT-(4+16));
if (challengesmenu.cache_secondrowlocked == true)
y += 8;
V_DrawFadeFill(
4,
y,
28 + offset,
(challengesmenu.cache_secondrowlocked ? 8 : 16),
0,
31,
challengetransparentstrength
);
for (i = 0; i < offset; i += 4)
{
V_DrawFill(4+1 + i, (BASEVIDHEIGHT-(4+16))+3, 2, 2, 15);
V_DrawFill(4+1 + i, (BASEVIDHEIGHT-(4+16))+8+3, 2, 2, 15);
V_DrawFill(4+1 + i, y+3, 2, 2, 15);
if (challengesmenu.cache_secondrowlocked == false)
V_DrawFill(4+1 + i, y+8+3, 2, 2, 15);
}
for (i = 0; i < 7; i++)
for (i = 0; i < CUPMENU_COLUMNS; i++)
{
if (templevelsearch.cup && id == i)
{
V_DrawFill(offset + 4 + (i*4), (BASEVIDHEIGHT-(4+16)), 4, 8, 0);
V_DrawFill(offset + 4 + (i*4), y, 4, 8, 0);
}
else if (i < maxid)
{
V_DrawFill(offset + 4+1 + (i*4), (BASEVIDHEIGHT-(4+16))+3, 2, 2, 0);
V_DrawFill(offset + 4+1 + (i*4), y+3, 2, 2, 0);
}
if (templevelsearch.cup && (templevelsearch.cup->id % 14) == i+7)
if (templevelsearch.cup && id == i+CUPMENU_COLUMNS)
{
V_DrawFill(offset + 4 + (i*4), (BASEVIDHEIGHT-(4+16))+8, 4, 8, 0);
V_DrawFill(offset + 4 + (i*4), y+8, 4, 8, 0);
}
else if (i+7 < maxid)
else if (challengesmenu.cache_secondrowlocked == true)
;
else if (i+CUPMENU_COLUMNS < maxid)
{
V_DrawFill(offset + 4+1 + (i*4), (BASEVIDHEIGHT-(4+16))+8+3, 2, 2, 0);
V_DrawFill(offset + 4+1 + (i*4), y+8+3, 2, 2, 0);
}
}

View file

@ -1388,6 +1388,39 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
return (skins[cn->requirement].records.wins >= (UINT32)cn->extrainfo1);
case UC_ALLCUPRECORDS:
{
cupheader_t *cup;
UINT8 difficulty = cn->extrainfo2;
if (gamestate == GS_LEVEL)
return false; // this one could be laggy with many cups available
if (difficulty > KARTGP_MASTER)
difficulty = KARTGP_MASTER;
for (cup = kartcupheaders; cup; cup = cup->next)
{
// Ok, achieved up to the desired cup.
if (cn->requirement == cup->id)
return true;
cupwindata_t *windata = &cup->windata[cn->extrainfo2];
// Did you actually get it?
if (windata->best_placement == 0)
return false;
// Sufficient placement?
if (cn->extrainfo1 && windata->best_placement > cn->extrainfo1)
return false;
}
// If we ended up here, check we were looking for all cups achieved.
return (cn->requirement == -1);
}
case UC_ALLCHAOS:
case UC_ALLSUPER:
case UC_ALLEMERALDS:
@ -2120,6 +2153,50 @@ static const char *M_GetConditionString(condition_t *cn)
work);
}
case UC_ALLCUPRECORDS:
{
const char *completetype = "Complete", *orbetter = "", *specialtext = NULL, *speedtext = "";
if (cn->extrainfo1 == 0)
;
else if (cn->extrainfo1 == 1)
completetype = "get Gold over";
else
{
if (cn->extrainfo1 == 2)
completetype = "get Silver";
else if (cn->extrainfo1 == 3)
completetype = "get Bronze";
orbetter = " or better over";
}
if (cn->extrainfo2 == KARTSPEED_NORMAL)
{
speedtext = " on Normal";
}
else if (cn->extrainfo2 == KARTSPEED_HARD)
{
speedtext = " on Hard";
}
else if (cn->extrainfo2 == KARTGP_MASTER)
{
if (M_SecretUnlocked(SECRET_MASTERMODE, true))
speedtext = " on Master";
else
speedtext = " on ???";
}
if (cn->requirement == -1)
specialtext = "every Cup";
else if (M_CupSecondRowLocked() == true && cn->requirement+1 >= CUPMENU_COLUMNS)
specialtext = "the first ??? Cups";
if (specialtext != NULL)
return va("GRAND PRIX: %s%s %s%s", completetype, orbetter, specialtext, speedtext);
return va("GRAND PRIX: %s%s the first %d Cups%s", completetype, orbetter, cn->requirement, speedtext);
}
case UC_ALLCHAOS:
case UC_ALLSUPER:
case UC_ALLEMERALDS:
@ -2138,17 +2215,17 @@ static const char *M_GetConditionString(condition_t *cn)
/*if (cn->requirement == KARTSPEED_NORMAL) -- Emeralds can not be collected on Easy
{
speedtext = " on Normal difficulty";
speedtext = " on Normal";
}
else*/
if (cn->requirement == KARTSPEED_HARD)
{
speedtext = " on Hard difficulty";
speedtext = " on Hard";
}
else if (cn->requirement == KARTGP_MASTER)
{
if (M_SecretUnlocked(SECRET_MASTERMODE, true))
speedtext = " on Master difficulty";
speedtext = " on Master";
else
speedtext = " on ???";
}
@ -2401,16 +2478,16 @@ static const char *M_GetConditionString(condition_t *cn)
if (cn->requirement == KARTSPEED_NORMAL)
{
speedtext = "on Normal difficulty";
speedtext = "on Normal";
}
else if (cn->requirement == KARTSPEED_HARD)
{
speedtext = "on Hard difficulty";
speedtext = "on Hard";
}
else if (cn->requirement == KARTGP_MASTER)
{
if (M_SecretUnlocked(SECRET_MASTERMODE, true))
speedtext = "on Master difficulty";
speedtext = "on Master";
else
speedtext = "on ???";
}
@ -3190,6 +3267,33 @@ boolean M_CupLocked(cupheader_t *cup)
return false;
}
boolean M_CupSecondRowLocked(void)
{
// The following was pre-optimised for cached behaviour.
// It would need a refactor if the cache system were to
// change, maybe to iterate over unlockable_t instead.
cupheader_t *cup;
for (cup = kartcupheaders; cup; cup = cup->next)
{
// Only important for the second row.
if ((cup->id % (CUPMENU_COLUMNS * CUPMENU_ROWS)) < CUPMENU_COLUMNS)
continue;
// Only important for ones that can be locked.
if (cup->cache_cuplock == MAXUNLOCKABLES)
continue;
// If it's NOT unlocked, can't be used as proof of unlock.
if (!M_CheckNetUnlockByID(cup->cache_cuplock))
continue;
// Okay, at least one cup on the second row is unlocked!
return false;
}
return true;
}
boolean M_MapLocked(UINT16 mapnum)
{
// Don't lock maps in dedicated servers.

View file

@ -47,6 +47,8 @@ typedef enum
UC_CHARACTERWINS, // CHARACTERWINS [character] [x rounds]
UC_ALLCUPRECORDS, // ALLCUPRECORDS [cup to complete up to] [minimum position] [minimum difficulty]
UC_ALLCHAOS, // ALLCHAOS [minimum difficulty]
UC_ALLSUPER, // ALLSUPER [minimum difficulty]
UC_ALLEMERALDS, // ALLEMERALDS [minimum difficulty]
@ -437,6 +439,7 @@ UINT16 M_CompletionEmblems(void);
boolean M_CheckNetUnlockByID(UINT16 unlockid);
boolean M_SecretUnlocked(INT32 type, boolean local);
boolean M_CupLocked(cupheader_t *cup);
boolean M_CupSecondRowLocked(void);
boolean M_MapLocked(UINT16 mapnum);
INT32 M_CountMedals(boolean all, boolean extraonly);

View file

@ -58,6 +58,8 @@ static void M_UpdateChallengeGridVisuals(void)
{
UINT16 i;
challengesmenu.cache_secondrowlocked = M_CupSecondRowLocked();
challengesmenu.unlockcount[CMC_UNLOCKED] = 0;
challengesmenu.unlockcount[CMC_TOTAL] = 0;

View file

@ -60,7 +60,7 @@ static void M_StatisticsMaps(void)
if (M_CupLocked(cup))
continue;
for (i = 0; i < CUPCACHE_MAX; i++)
for (i = 0; i < CUPCACHE_PODIUM; i++)
{
if (cup->cachedlevels[i] >= nummapheaders)
continue;

View file

@ -214,7 +214,9 @@ void M_CupSelectHandler(INT32 choice)
M_SetMenuDelay(pid);
}
if (menucmd[pid].dpad_ud > 0)
if (cupgrid.cache_secondrowlocked == true)
; // No up/down for you!
else if (menucmd[pid].dpad_ud > 0)
{
cupgrid.y++;
if (cupgrid.y >= CUPMENU_ROWS)

View file

@ -114,7 +114,7 @@ UINT16 M_CountLevelsToShowInList(levelsearch_t *levelsearch)
if (levelsearch->checklocked && M_CupLocked(levelsearch->cup))
return 0;
for (i = 0; i < CUPCACHE_MAX; i++)
for (i = 0; i < CUPCACHE_PODIUM; i++)
{
if (!M_CanShowLevelInList(levelsearch->cup->cachedlevels[i], levelsearch))
continue;
@ -158,13 +158,13 @@ UINT16 M_GetFirstLevelInList(UINT8 *i, levelsearch_t *levelsearch)
{
if (levelsearch->checklocked && M_CupLocked(levelsearch->cup))
{
*i = CUPCACHE_MAX;
*i = CUPCACHE_PODIUM;
return NEXTMAP_INVALID;
}
*i = 0;
mapnum = NEXTMAP_INVALID;
for (; *i < CUPCACHE_MAX; (*i)++)
for (; *i < CUPCACHE_PODIUM; (*i)++)
{
if (!M_CanShowLevelInList(levelsearch->cup->cachedlevels[*i], levelsearch))
continue;
@ -194,7 +194,7 @@ UINT16 M_GetNextLevelInList(UINT16 mapnum, UINT8 *i, levelsearch_t *levelsearch)
{
mapnum = NEXTMAP_INVALID;
(*i)++;
for (; *i < CUPCACHE_MAX; (*i)++)
for (; *i < CUPCACHE_PODIUM; (*i)++)
{
if (!M_CanShowLevelInList(levelsearch->cup->cachedlevels[*i], levelsearch))
continue;
@ -299,18 +299,28 @@ boolean M_LevelListFromGametype(INT16 gt)
if (levellist.levelsearch.cupmode)
{
const boolean secondrowlocked = M_CupSecondRowLocked();
if (cupgrid.cache_secondrowlocked != secondrowlocked)
{
cupgrid.cache_secondrowlocked = secondrowlocked;
if (cupgrid.y || cupgrid.pageno)
{
// Prevent softlock, reset to start
cupgrid.x = cupgrid.y = cupgrid.pageno = 0;
}
}
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
size_t currentid = 0, highestunlockedid = 0;
const size_t pagelen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS);
boolean foundany = false, currentvalid = false;
size_t deltaid = 0;
G_GetBackupCupData(
cupgrid.grandprix == true
&& cv_splitplayers.value <= 1
);
templevelsearch.cup = kartcupheaders;
#if 0
// Make sure there's valid cups before going to this menu. -- rip sweet prince
if (templevelsearch.cup == NULL)
@ -357,8 +367,89 @@ boolean M_LevelListFromGametype(INT16 gt)
cupgrid.pageno = currentid / (CUPMENU_COLUMNS * CUPMENU_ROWS); \
currentvalid = true;
while (templevelsearch.cup)
#define GRID_TIDYLOCKED(rewind) \
currentid -= rewind; \
memset(&cupgrid.builtgrid[currentid], 0, pagelen); \
deltaid = 0;
boolean lostandfoundready = true;
// foundanythispage SHOULD start out as false... but if
// nothing is unlocked, the first page should never be wiped!
boolean foundanythispage = true;
templevelsearch.cup = kartcupheaders;
while (true)
{
// Handle reaching the end of the base-game cups.
if (lostandfoundready == true
&& (
templevelsearch.cup == NULL
|| templevelsearch.cup->id == basenumkartcupheaders
)
)
{
lostandfoundready = false;
if (deltaid != 0 && foundanythispage == false)
{
GRID_TIDYLOCKED(deltaid);
}
size_t olddelta = deltaid;
if (cupgrid.grandprix == false)
{
cupheader_t *restore = templevelsearch.cup;
templevelsearch.cup = &dummy_lostandfound;
templevelsearch.checklocked = true;
if (M_GetFirstLevelInList(&temp, &templevelsearch) != NEXTMAP_INVALID)
{
foundany = foundanythispage = 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++;
deltaid = currentid % (CUPMENU_COLUMNS * CUPMENU_ROWS);
}
templevelsearch.cup = restore;
}
// Lost and Found marks the transition point between base
// and custom cups. Always force a page break between these
// (unless LnF is the only "cup" on the page, for sanity).
if (
(deltaid == 0) // a new page already
|| (olddelta == 0 && deltaid == 1) // LnF is first and only entry
)
; // this page layout is fine
else
{
if (foundanythispage == false)
{
GRID_TIDYLOCKED(deltaid);
}
else
{
currentid += (CUPMENU_COLUMNS * CUPMENU_ROWS) - deltaid;
deltaid = 0;
foundanythispage = false;
}
}
}
if (templevelsearch.cup == NULL)
break;
templevelsearch.checklocked = false;
if (!M_CountLevelsToShowInList(&templevelsearch))
{
@ -374,6 +465,7 @@ boolean M_LevelListFromGametype(INT16 gt)
templevelsearch.checklocked = true;
if (M_GetFirstLevelInList(&temp, &templevelsearch) != NEXTMAP_INVALID)
{
foundanythispage = true;
highestunlockedid = currentid;
if (Playing()
@ -385,37 +477,34 @@ boolean M_LevelListFromGametype(INT16 gt)
}
}
currentid++;
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;
currentid++;
deltaid = currentid % (CUPMENU_COLUMNS * CUPMENU_ROWS);
if (M_GetFirstLevelInList(&temp, &templevelsearch) != NEXTMAP_INVALID)
if (secondrowlocked == true)
{
foundany = true;
GRID_INSERTCUP;
highestunlockedid = currentid;
if (Playing()
? (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == NULL)
: (gt == -1 && levellist.levelsearch.cup == templevelsearch.cup))
// If the second row is locked and you've reached it, skip onward.
if (deltaid >= CUPMENU_COLUMNS)
{
GRID_FOCUSCUP;
currentid += (CUPMENU_COLUMNS * CUPMENU_ROWS) - deltaid;
deltaid = 0;
}
currentid++;
}
templevelsearch.cup = NULL;
if (deltaid == 0)
{
if (foundanythispage == false)
{
GRID_TIDYLOCKED((CUPMENU_COLUMNS * CUPMENU_ROWS));
}
foundanythispage = false;
}
}
#undef GRID_INSERTCUP
#undef GRID_FOCUSCUP
#undef GRID_TIDYLOCKED
if (foundany == false)
{