From be38ba15111f9dd88a8eff74fcbfbbcae07b9d42 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 4 Dec 2022 15:30:38 +0000 Subject: [PATCH] A heaping of polish * Challengegrid now loops and scrolls horizontally. - Scroll position currently tied directly to selected row/column, but can (and will) be seperated relatively easily later. - In `DEVELOP` builds always scrolls - but in release builds, if someone makes a custom gamedata with less than 20 challengegrid columns (BASEVIDWIDTH/16), it'll remain static. * Challenge ticker now automatically unlocks all pending at a rate of ~one per second. - Based on VC discussion and Kirby Air Ride. - Since no user input necessary, screen is now part-faded when unlocks are pending. * Drawing a specific grid tile is now its own `k_menudraw.c` function. * There is now a light grey grid around unselected tiles. * Unlock explosions now use the tile's colour or, if not provided, the current profile's color. --- src/k_menu.h | 5 +- src/k_menudef.c | 2 +- src/k_menudraw.c | 271 +++++++++++++++++++++++++++++------------------ src/k_menufunc.c | 100 +++++++++-------- src/m_cond.c | 6 +- src/m_cond.h | 6 ++ 6 files changed, 241 insertions(+), 149 deletions(-) diff --git a/src/k_menu.h b/src/k_menu.h index 49576eaad..81de34e74 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -656,7 +656,7 @@ extern UINT8 setup_maxpage; #define CSEXPLOSIONS 48 extern struct setup_explosions_s { - UINT16 x, y; + INT16 x, y; UINT8 tics; UINT16 color; } setup_explosions[CSEXPLOSIONS]; @@ -1084,7 +1084,7 @@ void M_DrawAddons(void); // Challenges menu: #define UNLOCKTIME 5 -#define MAXUNLOCKTIME 35 +#define MAXUNLOCKTIME TICRATE // Keep track of some pause menu data for visual goodness. extern struct challengesmenu_s { @@ -1092,6 +1092,7 @@ extern struct challengesmenu_s { tic_t ticker; // How long the menu's been open for INT16 offset; // To make the icons move smoothly when we transition! + UINT8 fade; UINT8 currentunlock; tic_t unlockanim; diff --git a/src/k_menudef.c b/src/k_menudef.c index 53c55a415..9cbbdf932 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -1756,7 +1756,7 @@ menu_t MISC_ChallengesDef = { &MainDef, 0, MISC_ChallengesMenu, - 14, 32, + BASEVIDWIDTH/2, 32, 0, 0, 98, 0, M_DrawChallenges, diff --git a/src/k_menudraw.c b/src/k_menudraw.c index ea0bed6e4..625deb577 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1480,7 +1480,7 @@ static void M_DrawCharSelectPreview(UINT8 num) } } -static void M_DrawCharSelectExplosions(boolean charsel, UINT16 basex, UINT16 basey) +static void M_DrawCharSelectExplosions(boolean charsel, INT16 basex, INT16 basey) { UINT8 i; INT16 quadx = 0, quady = 0; @@ -4480,16 +4480,123 @@ void M_DrawAddons(void) #undef addonsseperation -void M_DrawChallenges(void) +#define challengesbordercolor 8 + +static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili) { - INT32 x = currentMenu->x, y = currentMenu->y; - UINT8 i, j, id, num, work; - const char *str; - INT16 offset; unlockable_t *ref = NULL; patch_t *pat; UINT8 *colormap; fixed_t siz; + UINT8 id, num, work; + + id = (i * CHALLENGEGRIDHEIGHT) + j; + num = gamedata->challengegrid[id]; + + // Empty spots in the grid are always unconnected. + if (num >= MAXUNLOCKABLES) + { + V_DrawFill(x, y, 16, 16, 27); + ref = NULL; + goto drawborder; + } + + // Okay, this is what we want to draw. + ref = &unlockables[num]; + + // ...unless we simply aren't unlocked yet. + if ((gamedata->unlocked[num] == false) + || (challengesmenu.pending && num == challengesmenu.currentunlock && challengesmenu.unlockanim <= UNLOCKTIME)) + { + work = (ref->majorunlock) ? 2 : 1; + V_DrawFill(x, y, 16*work, 16*work, + ((challengesmenu.extradata[id] == CHE_HINT) ? 134 : 12)); + goto drawborder; + } + + pat = missingpat; + colormap = NULL; + if (ref->icon != NULL && ref->icon[0]) + { + pat = W_CachePatchName(ref->icon, PU_CACHE); + if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) + { + colormap = R_GetTranslationColormap(TC_DEFAULT, ref->color, GTC_MENUCACHE); + } + } + else switch (ref->type) + { + case SECRET_SKIN: + { + INT32 skin = M_UnlockableSkinNum(ref); + if (skin != -1) + { + colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); + pat = faceprefix[skin][(ref->majorunlock) ? FACE_WANTED : FACE_RANK]; + } + break; + } + case SECRET_FOLLOWER: + { + INT32 skin = M_UnlockableFollowerNum(ref); + if (skin != -1) + { + UINT16 col = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value); + colormap = R_GetTranslationColormap(skin, col, GTC_MENUCACHE); + pat = W_CachePatchName(followers[skin].icon, PU_CACHE); + } + break; + } + default: + { + pat = W_CachePatchName(va("UN_RR00%c", ref->majorunlock ? 'B' : 'A'), PU_CACHE); + if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) + { + //CONS_Printf(" color for %d is %s\n", num, skincolors[unlockables[num].color].name); + colormap = R_GetTranslationColormap(TC_RAINBOW, ref->color, GTC_MENUCACHE); + } + break; + } + } + + siz = (SHORT(pat->width) << FRACBITS); + siz = FixedDiv(((ref->majorunlock) ? 32 : 16) << FRACBITS, siz); + + V_DrawFixedPatch( + x*FRACUNIT, y*FRACUNIT, + siz, + 0, pat, + colormap + ); + +drawborder: + if (!hili) + { + work = 16 * ((ref && ref->majorunlock) ? 2 : 1); + // Horizontal + V_DrawFill(x, y , work, 1, challengesbordercolor); + V_DrawFill(x, y + work-1, work, 1, challengesbordercolor); + // Vertical + V_DrawFill(x , y+1, 1, work-2, challengesbordercolor); + V_DrawFill(x + work-1, y+1, 1, work-2, challengesbordercolor); + return; + } + + V_DrawFixedPatch( + x*FRACUNIT, y*FRACUNIT, + ((ref != NULL && ref->majorunlock) ? FRACUNIT*2 : FRACUNIT), + 0, kp_facehighlight[(challengesmenu.ticker / 4) % 8], + NULL + ); +} + +void M_DrawChallenges(void) +{ + INT32 x = currentMenu->x, explodex, selectx; + INT32 y = currentMenu->y; + INT16 i, j; + const char *str; + INT16 offset; { patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE); @@ -4498,119 +4605,79 @@ void M_DrawChallenges(void) if (!gamedata->challengegrid) { - V_DrawString(x, y, V_REDMAP, "No challenges available!?"); + V_DrawCenteredString(x, y, V_REDMAP, "No challenges available!?"); goto challengedesc; } - for (i = 0; i < gamedata->challengegridwidth; i++) + x -= 16; + + if (challengegridloops) + { + i = challengesmenu.col; + explodex = x - (i*16); + + while (x < BASEVIDWIDTH-16) + { + i = (i + 1) % gamedata->challengegridwidth; + x += 16; + } + } + else + { + if (gamedata->challengegridwidth & 1) + x += 8; + + i = gamedata->challengegridwidth-1; + explodex = x - (i*16)/2; + x += (i*16)/2; + + V_DrawFill(0, currentMenu->y, explodex, (CHALLENGEGRIDHEIGHT*16), challengesbordercolor); + V_DrawFill((x+16), currentMenu->y, BASEVIDWIDTH - (x+16), (CHALLENGEGRIDHEIGHT*16), challengesbordercolor); + } + + selectx = explodex + (challengesmenu.hilix*16); + + V_DrawFill(0, (currentMenu->y)-1 , BASEVIDWIDTH, 1, challengesbordercolor); + V_DrawFill(0, (currentMenu->y) + (CHALLENGEGRIDHEIGHT*16), BASEVIDWIDTH, 1, challengesbordercolor); + while (i >= 0 && x >= -32) { y = currentMenu->y-16; for (j = 0; j < CHALLENGEGRIDHEIGHT; j++) { y += 16; - id = (i * CHALLENGEGRIDHEIGHT) + j; - if (challengesmenu.extradata[id] & CHE_DONTDRAW) + if (challengesmenu.extradata[(i * CHALLENGEGRIDHEIGHT) + j] & CHE_DONTDRAW) { continue; } - num = gamedata->challengegrid[id]; - - // Empty spots in the grid are always unconnected. - if (num >= MAXUNLOCKABLES) + if (x == selectx && j == challengesmenu.hiliy) { - V_DrawFill(x, y, 16, 16, 27); - ref = NULL; - goto drawborder; - } - - // Okay, this is what we want to draw. - ref = &unlockables[num]; - - // ...unless we simply aren't unlocked yet. - if ((gamedata->unlocked[num] == false) - || (challengesmenu.pending && num == challengesmenu.currentunlock && challengesmenu.unlockanim <= UNLOCKTIME)) - { - work = (ref->majorunlock) ? 2 : 1; - V_DrawFill(x, y, 16*work, 16*work, - ((challengesmenu.extradata[id] == CHE_HINT) ? 130 : 12) - + ((i & work) != (j & work) ? 0 : 2) + (work-1)); // funny checkerboard pattern - goto drawborder; - } - - pat = missingpat; - colormap = NULL; - if (ref->icon != NULL) - { - pat = W_CachePatchName(ref->icon, PU_CACHE); - if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) - { - colormap = R_GetTranslationColormap(TC_DEFAULT, ref->color, GTC_MENUCACHE); - } - } - else switch (ref->type) - { - case SECRET_SKIN: - { - INT32 skin = M_UnlockableSkinNum(ref); - if (skin != -1) - { - colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE); - pat = faceprefix[skin][(ref->majorunlock) ? FACE_WANTED : FACE_RANK]; - } - break; - } - case SECRET_FOLLOWER: - { - INT32 skin = M_UnlockableFollowerNum(ref); - if (skin != -1) - { - UINT16 col = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value); - colormap = R_GetTranslationColormap(skin, col, GTC_MENUCACHE); - pat = W_CachePatchName(followers[skin].icon, PU_CACHE); - } - break; - } - default: - { - pat = W_CachePatchName(va("UN_RR00%c", ref->majorunlock ? 'B' : 'A'), PU_CACHE); - if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) - { - CONS_Printf(" color for %d is %s\n", num, skincolors[unlockables[num].color].name); - colormap = R_GetTranslationColormap(TC_RAINBOW, ref->color, GTC_MENUCACHE); - } - break; - } - } - - siz = (SHORT(pat->width) << FRACBITS); - siz = FixedDiv(((ref->majorunlock) ? 32 : 16) << FRACBITS, siz); - - V_DrawFixedPatch( - x*FRACUNIT, y*FRACUNIT, - siz, - 0, pat, - colormap - ); - -drawborder: - if (i != challengesmenu.hilix) - continue; - if (j != challengesmenu.hiliy) continue; + } - V_DrawFixedPatch( - x*FRACUNIT, y*FRACUNIT, - ((ref != NULL && ref->majorunlock) ? FRACUNIT*2 : FRACUNIT), - 0, kp_facehighlight[(challengesmenu.ticker / 4) % 8], - NULL - ); + M_DrawChallengeTile(i, j, x, y, false); + } + + x -= 16; + i--; + if (challengegridloops && i < 0) + { + i = (i + gamedata->challengegridwidth) + % gamedata->challengegridwidth; } - x += 16; } - M_DrawCharSelectExplosions(false, currentMenu->x, currentMenu->y); + if (challengesmenu.fade) + V_DrawFadeScreen(31, challengesmenu.fade); + + M_DrawChallengeTile( + challengesmenu.hilix, + challengesmenu.hiliy, + selectx, + currentMenu->y + (challengesmenu.hiliy*16), + true); + M_DrawCharSelectExplosions(false, explodex, currentMenu->y); challengedesc: y = 120; @@ -4632,6 +4699,6 @@ challengedesc: offset = V_LSTitleLowStringWidth(str, 0) / 2; V_DrawLSTitleLowString(BASEVIDWIDTH/2 - offset, y+6, 0, str); - if (challengesmenu.unlockanim >= MAXUNLOCKTIME) - V_DrawThinString(20, 120 + 60, V_ALLOWLOWERCASE, va("Press (%c)", challengesmenu.pending ? 'A' : 'B')); + if (!challengesmenu.fade) + V_DrawThinString(20, 120 + 60, V_ALLOWLOWERCASE, "Press (B)"); } diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 86cc29ffe..185a47ad3 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -2289,21 +2289,11 @@ static void M_SetupReadyExplosions(boolean charsel, UINT16 basex, UINT16 basey, if ((y < 0 || y >= maxy)) continue; - if (/*charsel &&*/ (x < 0 || x >= maxx)) - continue; - - /*if (!charsel) + if (charsel || !challengegridloops) { - while (x < 0) - { - x += maxx; - } - - while (x >= maxx) - { - x -= maxx; - } - }*/ + if (x < 0 || x >= maxx) + continue; + } setup_explosions[e].tics = t; setup_explosions[e].color = color; @@ -6960,6 +6950,7 @@ void M_ChallengesTick(void) if (challengesmenu.pending && challengesmenu.requestnew) { + challengesmenu.requestnew = false; if ((newunlock = M_GetNextAchievedUnlock()) < MAXUNLOCKABLES) { challengesmenu.currentunlock = newunlock; @@ -6991,15 +6982,14 @@ void M_ChallengesTick(void) G_SaveGameData(); } } - else if (challengesmenu.unlockanim >= MAXUNLOCKTIME) + else if (challengesmenu.pending && challengesmenu.fade < 5) + challengesmenu.fade++; + else if (challengesmenu.pending) { - ; - } - else - { - challengesmenu.unlockanim++; - if (challengesmenu.pending - && challengesmenu.currentunlock < MAXUNLOCKABLES + if (++challengesmenu.unlockanim >= MAXUNLOCKTIME) + challengesmenu.requestnew = true; + + if (challengesmenu.currentunlock < MAXUNLOCKABLES && challengesmenu.unlockanim == UNLOCKTIME) { gamedata->unlocked[challengesmenu.currentunlock] = true; @@ -7008,18 +6998,54 @@ void M_ChallengesTick(void) challengesmenu.extradata = M_ChallengeGridExtraData(); S_StartSound(NULL, sfx_s3k4e); - M_SetupReadyExplosions(false, challengesmenu.col, challengesmenu.row, SKINCOLOR_KETCHUP); - if (unlockables[challengesmenu.currentunlock].majorunlock) { - i = challengesmenu.col+1; - if (i == gamedata->challengegridwidth) - i = 0; - M_SetupReadyExplosions(false, i, challengesmenu.row+1, SKINCOLOR_KETCHUP); + unlockable_t *ref = &unlockables[challengesmenu.currentunlock]; + UINT16 bombcolor = SKINCOLOR_NONE; + + if (ref->color != SKINCOLOR_NONE && ref->color < numskincolors) + { + bombcolor = ref->color; + } + else switch (ref->type) + { + case SECRET_SKIN: + { + INT32 skin = M_UnlockableSkinNum(ref); + if (skin != -1) + { + bombcolor = skins[skin].prefcolor; + } + break; + } + case SECRET_FOLLOWER: + { + INT32 skin = M_UnlockableFollowerNum(ref); + if (skin != -1) + { + bombcolor = K_GetEffectiveFollowerColor(followers[skin].defaultcolor, cv_playercolor[0].value); + } + break; + } + default: + break; + } + + if (bombcolor == SKINCOLOR_NONE) + { + bombcolor = cv_playercolor[0].value; + } + + i = (ref->majorunlock && M_RandomChance(FRACUNIT/2)) ? 1 : 0; + M_SetupReadyExplosions(false, challengesmenu.col, challengesmenu.row+i, bombcolor); + if (ref->majorunlock) + { + M_SetupReadyExplosions(false, challengesmenu.col+1, challengesmenu.row+(1-i), bombcolor); + } } } } - - challengesmenu.requestnew = false; + else if (challengesmenu.fade > 0) + challengesmenu.fade--; } boolean M_ChallengesInputs(INT32 ch) @@ -7069,18 +7095,8 @@ boolean M_ChallengesInputs(INT32 ch) return true; } #endif - else if (challengesmenu.pending) - { - if (challengesmenu.unlockanim < MAXUNLOCKTIME) - { - ; - } - else if ((M_MenuConfirmPressed(pid) || start)) - { - challengesmenu.requestnew = true; - } - return true; - } + else if (challengesmenu.fade) + ; else { if (M_MenuBackPressed(pid) || start) diff --git a/src/m_cond.c b/src/m_cond.c index 74e8c09fd..20d57d85e 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -117,7 +117,9 @@ void M_PopulateChallengeGrid(void) if (nummajorunlocks) { // You lose one from CHALLENGEGRIDHEIGHT because it is impossible to place a 2-high tile on the bottom row. - UINT16 numspots = gamedata->challengegridwidth * (CHALLENGEGRIDHEIGHT-1); + // You lose one from the width if it doesn't loop. + UINT16 numspots = (gamedata->challengegridwidth - (challengegridloops ? 0 : 1)) + * (CHALLENGEGRIDHEIGHT-1); // 0 is row, 1 is column INT16 quickcheck[numspots][2]; @@ -323,7 +325,7 @@ UINT8 *M_ChallengeGridExtraData(void) if (work == num) { - if (!idchange && (i > 0 || gamedata->challengegridwidth > 2)) + if (!idchange && (i > 0 || challengegridloops)) { //CONS_Printf(" %d - %d to left of %d is valid\n", work, tempid, id); // If we haven't already updated our id, it's the one to our left. diff --git a/src/m_cond.h b/src/m_cond.h index d7445cd68..5854808c8 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -121,6 +121,12 @@ typedef struct #define MAXUNLOCKABLES MAXCONDITIONSETS #define CHALLENGEGRIDHEIGHT 5 +#ifdef DEVELOP +#define CHALLENGEGRIDLOOPWIDTH 3 +#else +#define CHALLENGEGRIDLOOPWIDTH (BASEVIDWIDTH/16) +#endif +#define challengegridloops (gamedata->challengegridwidth >= CHALLENGEGRIDLOOPWIDTH) // GAMEDATA STRUCTURE // Everything that would get saved in gamedata.dat