diff --git a/src/doomstat.h b/src/doomstat.h index efce0e5d6..1107aef97 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -53,6 +53,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 { diff --git a/src/k_menu.h b/src/k_menu.h index e4700187a..cbc3c899a 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -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); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index ca030b7a1..c6125b809 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -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)); @@ -5686,40 +5703,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); } } diff --git a/src/m_cond.c b/src/m_cond.c index f1ae5068e..c3cfda79a 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -3190,6 +3190,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. diff --git a/src/m_cond.h b/src/m_cond.h index 2b20bb769..d7445a5aa 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -437,6 +437,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); diff --git a/src/menus/extras-challenges.c b/src/menus/extras-challenges.c index 92b4d48ee..da5dc2bd1 100644 --- a/src/menus/extras-challenges.c +++ b/src/menus/extras-challenges.c @@ -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; diff --git a/src/menus/transient/cup-select.c b/src/menus/transient/cup-select.c index 69e155592..0f2f75239 100644 --- a/src/menus/transient/cup-select.c +++ b/src/menus/transient/cup-select.c @@ -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) diff --git a/src/menus/transient/level-select.c b/src/menus/transient/level-select.c index 8929e25b8..a7cf5d197 100644 --- a/src/menus/transient/level-select.c +++ b/src/menus/transient/level-select.c @@ -299,10 +299,21 @@ 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; + boolean foundany = false, foundanythispage = false, currentvalid = false; G_GetBackupCupData( cupgrid.grandprix == true @@ -374,6 +385,7 @@ boolean M_LevelListFromGametype(INT16 gt) templevelsearch.checklocked = true; if (M_GetFirstLevelInList(&temp, &templevelsearch) != NEXTMAP_INVALID) { + foundanythispage = true; highestunlockedid = currentid; if (Playing() @@ -386,6 +398,28 @@ boolean M_LevelListFromGametype(INT16 gt) } currentid++; + + // If the second row is locked and you've reached it, skip onward. + if (secondrowlocked == true) + { + size_t deltaid = currentid % (CUPMENU_COLUMNS * CUPMENU_ROWS); + if (deltaid >= CUPMENU_COLUMNS) + { + currentid += (CUPMENU_COLUMNS * CUPMENU_ROWS) - deltaid; + } + } + + // If you've gone a full page without anything valid, compress it down! + if ((currentid % (CUPMENU_COLUMNS * CUPMENU_ROWS)) == 0) + { + if (foundanythispage == false) + { + currentid -= (CUPMENU_COLUMNS * CUPMENU_ROWS); + memset(&cupgrid.builtgrid[currentid], 0, pagelen); + } + foundanythispage = false; + } + templevelsearch.cup = templevelsearch.cup->next; }