Icon selection + Extras menu access

* Icon selection
    * You can use up, down, left, right, etc to select icons on the Challenges menu
    * The text at the top changes based on the highlighted icon
        * This text is now ??? if not yet unlocked
    * Uses the border for character rank icons
* Challenges are now accessible on the Extras menu alongside Addons and Replay Hut.
    * Previously there was a "Extras Checklist" dummy which did nothing when selected
    * Now I won't have to clear my gamedata every time I want to check this menu!
* M_ChallengeGridExtraData's array is modified to now contain specific info on whether a given tile is connected to above or left (or both).
This commit is contained in:
toaster 2022-12-02 20:13:52 +00:00
parent 85160b1dc1
commit ac15d4caa3
8 changed files with 311 additions and 50 deletions

View file

@ -69,7 +69,7 @@ static patch_t *kp_racefinish[6];
static patch_t *kp_positionnum[10][2][2]; // number, overlay or underlay, splitscreen
static patch_t *kp_facenum[MAXPLAYERS+1];
static patch_t *kp_facehighlight[8];
patch_t *kp_facehighlight[8];
static patch_t *kp_nocontestminimap;
static patch_t *kp_spbminimap;

View file

@ -39,4 +39,6 @@ void K_drawKartFreePlay(void);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode);
void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol);
extern patch_t *kp_facehighlight[8];
#endif

View file

@ -1091,11 +1091,15 @@ extern struct challengesmenu_s {
UINT8 currentunlock;
tic_t unlockanim;
UINT8 row, col, hilix, hiliy;
UINT8 *extradata;
boolean pending;
} challengesmenu;
menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu);
void M_Challenges(INT32 choice);
void M_DrawChallenges(void);
void M_ChallengesTick(void);
boolean M_ChallengesInputs(INT32 ch);

View file

@ -1496,14 +1496,14 @@ menuitem_t EXTRAS_Main[] =
{IT_STRING | IT_CALL, "Addons", "Add files to customize your experience.",
NULL, {.routine = M_Addons}, 0, 0},
{IT_STRING | IT_CALL, "Challenges", "View the requirements for some of the secret content you can unlock!",
NULL, {.routine = M_Challenges}, 0, 0},
{IT_STRING | IT_CALL, "Replay Hut", "Play the replays you've saved throughout your many races & battles!",
NULL, {.routine = M_ReplayHut}, 0, 0},
{IT_STRING | IT_CALL, "Statistics", "Look back on some of your greatest achievements such as your playtime and wins!",
NULL, {NULL}, 0, 0},
{IT_STRING | IT_TRANSTEXT, "Extras Checklist", "View the requirement for some of the secret content you can unlock!",
NULL, {NULL}, 0, 0},
};
// the extras menu essentially reuses the options menu stuff

View file

@ -600,10 +600,10 @@ static void M_DrawMenuTooltips(void)
// Used for the secrets menu, to hide yet-to-be-unlocked stuff.
static const char *M_CreateSecretMenuOption(const char *str)
{
static char qbuf[32];
static char qbuf[64];
int i;
for (i = 0; i < 31; ++i)
for (i = 0; i < 63; ++i)
{
if (!str[i])
{
@ -616,7 +616,7 @@ static const char *M_CreateSecretMenuOption(const char *str)
qbuf[i] = ' ';
}
qbuf[31] = '\0';
qbuf[63] = '\0';
return qbuf;
}
@ -4471,19 +4471,21 @@ void M_DrawChallenges(void)
if (challengesmenu.currentunlock < MAXUNLOCKABLES)
{
V_DrawThinString(x, y, V_ALLOWLOWERCASE, unlockables[challengesmenu.currentunlock].name);
if (challengesmenu.unlockanim >= UNLOCKTIME)
V_DrawThinString(x, y + 10, V_ALLOWLOWERCASE, "Press (A)");
const char *str = unlockables[challengesmenu.currentunlock].name;
if (!gamedata->unlocked[challengesmenu.currentunlock])
{
str = "???"; //M_CreateSecretMenuOption(str);
}
V_DrawThinString(x, y, V_ALLOWLOWERCASE, str);
}
else
{
V_DrawThinString(x, y, V_ALLOWLOWERCASE, va("pending = %c", challengesmenu.pending ? 'T' : 'F'));
if (challengesmenu.unlockanim >= UNLOCKTIME)
V_DrawThinString(x, y + 10, V_ALLOWLOWERCASE, "Press (B)");
V_DrawThinString(x, y, V_ALLOWLOWERCASE, "---");
}
if (challengesmenu.unlockanim >= UNLOCKTIME)
V_DrawThinString(x, y + 10, V_ALLOWLOWERCASE, va("Press (%c)", challengesmenu.pending ? 'A' : 'B'));
x = currentMenu->x;
y = currentMenu->y;
@ -4501,7 +4503,7 @@ void M_DrawChallenges(void)
y += 16;
id = (i * CHALLENGEGRIDHEIGHT) + j;
if (challengesmenu.extradata[id] == CHE_DONTDRAW)
if (challengesmenu.extradata[id] & CHE_DONTDRAW)
{
continue;
}
@ -4512,7 +4514,8 @@ void M_DrawChallenges(void)
if (num >= MAXUNLOCKABLES)
{
V_DrawFill(x, y, 16, 16, 27);
continue;
ref = NULL;
goto drawborder;
}
// Okay, this is what we want to draw.
@ -4526,7 +4529,7 @@ void M_DrawChallenges(void)
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
continue;
goto drawborder;
}
switch (ref->type)
@ -4551,6 +4554,19 @@ void M_DrawChallenges(void)
V_DrawString(x, y, V_ALLOWLOWERCASE, va("%c", ref->name[0]));
break;
}
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
);
}
x += 16;
}

View file

@ -775,22 +775,6 @@ static boolean M_PrevOpt(void)
return true;
}
static menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
{
M_UpdateUnlockablesAndExtraEmblems(false);
if (M_GetNextAchievedUnlock(false) < MAXUNLOCKABLES)
{
MISC_ChallengesDef.prevMenu = desiredmenu;
challengesmenu.pending = true;
challengesmenu.currentunlock = MAXUNLOCKABLES;
M_PopulateChallengeGrid();
return &MISC_ChallengesDef;
}
return desiredmenu;
}
//
// M_Responder
//
@ -6826,19 +6810,122 @@ void M_Manual(INT32 choice)
struct challengesmenu_s challengesmenu;
menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
{
M_UpdateUnlockablesAndExtraEmblems(false);
if (M_GetNextAchievedUnlock(false) < MAXUNLOCKABLES)
{
challengesmenu.pending = true;
MISC_ChallengesDef.prevMenu = desiredmenu;
}
if (challengesmenu.pending || desiredmenu == NULL)
{
challengesmenu.currentunlock = MAXUNLOCKABLES;
M_PopulateChallengeGrid();
return &MISC_ChallengesDef;
}
return desiredmenu;
}
void M_Challenges(INT32 choice)
{
UINT8 i;
(void)choice;
M_InterruptMenuWithChallenges(NULL);
MISC_ChallengesDef.prevMenu = currentMenu;
if (gamedata->challengegrid)
{
UINT8 selection[MAXUNLOCKABLES];
UINT8 numunlocks = 0;
// Get a random available unlockable.
for (i = 0; i < MAXUNLOCKABLES; i++)
{
if (!unlockables[i].conditionset)
{
continue;
}
if (!gamedata->unlocked[i])
{
continue;
}
selection[numunlocks++] = i;
}
if (!numunlocks)
{
// ...OK, get a random unlockable.
for (i = 0; i < MAXUNLOCKABLES; i++)
{
if (!unlockables[i].conditionset)
{
continue;
}
selection[numunlocks++] = i;
}
}
challengesmenu.currentunlock = selection[M_RandomKey(numunlocks)];
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
{
if (gamedata->challengegrid[i] != challengesmenu.currentunlock)
{
continue;
}
challengesmenu.col = challengesmenu.hilix = i/CHALLENGEGRIDHEIGHT;
challengesmenu.row = challengesmenu.hiliy = i%CHALLENGEGRIDHEIGHT;
break;
}
}
M_SetupNextMenu(&MISC_ChallengesDef, false);
}
void M_ChallengesTick(void)
{
UINT8 i, newunlock = MAXUNLOCKABLES;
challengesmenu.ticker++;
if (challengesmenu.pending && challengesmenu.currentunlock >= MAXUNLOCKABLES)
{
if ((challengesmenu.currentunlock = M_GetNextAchievedUnlock(true)) >= MAXUNLOCKABLES)
if ((newunlock = M_GetNextAchievedUnlock(true)) < MAXUNLOCKABLES)
{
challengesmenu.currentunlock = newunlock;
challengesmenu.unlockanim = 0;
if (gamedata->challengegrid)
{
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
{
if (gamedata->challengegrid[i] != challengesmenu.currentunlock)
{
continue;
}
challengesmenu.col = challengesmenu.hilix = i/CHALLENGEGRIDHEIGHT;
challengesmenu.row = challengesmenu.hiliy = i%CHALLENGEGRIDHEIGHT;
break;
}
}
}
else
{
challengesmenu.pending = false;
G_SaveGameData();
}
Z_Free(challengesmenu.extradata);
challengesmenu.extradata = M_ChallengeGridExtraData();
challengesmenu.extradata = NULL;
}
else if (challengesmenu.unlockanim >= UNLOCKTIME)
{
@ -6848,14 +6935,25 @@ void M_ChallengesTick(void)
{
challengesmenu.unlockanim++;
}
if (challengesmenu.extradata == NULL)
{
challengesmenu.extradata = M_ChallengeGridExtraData();
}
}
boolean M_ChallengesInputs(INT32 ch)
{
const UINT8 pid = 0;
boolean start = M_MenuButtonPressed(pid, MBT_START);
UINT8 i;
const boolean start = M_MenuButtonPressed(pid, MBT_START);
const boolean move = (menucmd[pid].dpad_ud || menucmd[pid].dpad_lr);
(void) ch;
if (!challengesmenu.extradata)
{
;
}
if (challengesmenu.unlockanim < UNLOCKTIME)
{
;
@ -6870,6 +6968,21 @@ boolean M_ChallengesInputs(INT32 ch)
Z_Free(challengesmenu.extradata);
challengesmenu.extradata = M_ChallengeGridExtraData();
challengesmenu.unlockanim = 0;
if (challengesmenu.currentunlock != MAXUNLOCKABLES)
{
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
{
if (gamedata->challengegrid[i] != challengesmenu.currentunlock)
{
continue;
}
challengesmenu.col = challengesmenu.hilix = i/CHALLENGEGRIDHEIGHT;
challengesmenu.row = challengesmenu.hiliy = i%CHALLENGEGRIDHEIGHT;
break;
}
}
return true;
}
#endif
@ -6878,19 +6991,142 @@ boolean M_ChallengesInputs(INT32 ch)
if ((M_MenuConfirmPressed(pid) || start))
{
challengesmenu.currentunlock = MAXUNLOCKABLES;
challengesmenu.unlockanim = 0;
}
return true;
}
else if (M_MenuBackPressed(pid) || start)
else
{
M_GoBack(0);
M_SetMenuDelay(pid);
if (M_MenuBackPressed(pid) || start)
{
M_GoBack(0);
M_SetMenuDelay(pid);
Z_Free(challengesmenu.extradata);
challengesmenu.extradata = NULL;
Z_Free(challengesmenu.extradata);
challengesmenu.extradata = NULL;
return true;
return true;
}
// Determine movement around the grid
if (move)
{
if (menucmd[pid].dpad_ud > 0)
{
i = 2;
while (i > 0)
{
if (challengesmenu.row < CHALLENGEGRIDHEIGHT-1)
{
challengesmenu.row++;
}
else
{
challengesmenu.row = 0;
}
if (!(challengesmenu.extradata[
(challengesmenu.col * CHALLENGEGRIDHEIGHT)
+ challengesmenu.row]
& CHE_CONNECTEDUP))
{
break;
}
i--;
}
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
else if (menucmd[pid].dpad_ud < 0)
{
i = (challengesmenu.extradata[
(challengesmenu.col * CHALLENGEGRIDHEIGHT)
+ challengesmenu.row]
& CHE_CONNECTEDUP) ? 2 : 1;
while (i > 0)
{
if (challengesmenu.row > 0)
{
challengesmenu.row--;
}
else
{
challengesmenu.row = CHALLENGEGRIDHEIGHT-1;
}
i--;
}
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
if (menucmd[pid].dpad_lr > 0)
{
i = 2;
while (i > 0)
{
if (challengesmenu.col < gamedata->challengegridwidth-1)
{
challengesmenu.col++;
}
else
{
challengesmenu.col = 0;
}
if (!(challengesmenu.extradata[
(challengesmenu.col * CHALLENGEGRIDHEIGHT)
+ challengesmenu.row]
& CHE_CONNECTEDLEFT))
{
break;
}
i--;
}
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
else if (menucmd[pid].dpad_lr < 0)
{
i = (challengesmenu.extradata[
(challengesmenu.col * CHALLENGEGRIDHEIGHT)
+ challengesmenu.row]
& CHE_CONNECTEDLEFT) ? 2 : 1;
while (i > 0)
{
if (challengesmenu.col > 0)
{
challengesmenu.col--;
}
else
{
challengesmenu.col = gamedata->challengegridwidth-1;
}
i--;
}
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
// After movement has been determined, figure out the current selection.
i = (challengesmenu.col * CHALLENGEGRIDHEIGHT) + challengesmenu.row;
challengesmenu.currentunlock = (gamedata->challengegrid[i]);
challengesmenu.hilix = challengesmenu.col;
challengesmenu.hiliy = challengesmenu.row;
if (challengesmenu.hiliy > 0 && (challengesmenu.extradata[i] & CHE_CONNECTEDUP))
{
challengesmenu.hiliy--;
}
if ((challengesmenu.extradata[i] & CHE_CONNECTEDLEFT))
{
if (challengesmenu.hilix > 0)
{
challengesmenu.hilix--;
}
else
{
challengesmenu.hilix = gamedata->challengegridwidth-1;
}
}
}
}
return true;

View file

@ -278,12 +278,13 @@ UINT8 *M_ChallengeGridExtraData(void)
work = gamedata->challengegrid[tempid];
if (work == num)
{
extradata[id] = CHE_DONTDRAW;
extradata[id] = CHE_CONNECTEDUP;
// Get the id to write extra hint data to.
// This check is safe because extradata's order of population
if (extradata[tempid] == CHE_DONTDRAW)
if (extradata[tempid] & CHE_CONNECTEDLEFT)
{
extradata[id] |= CHE_CONNECTEDLEFT;
//CONS_Printf(" %d - %d above %d is invalid, check to left\n", num, tempid, id);
if (i > 0)
{
@ -333,7 +334,7 @@ UINT8 *M_ChallengeGridExtraData(void)
{
extradata[tempid] = CHE_HINT;
}
extradata[id] = CHE_DONTDRAW;
extradata[id] = CHE_CONNECTEDLEFT;
id = tempid;
}
/*else

View file

@ -176,9 +176,11 @@ extern UINT32 unlocktriggers;
void M_NewGameDataStruct(void);
void M_PopulateChallengeGrid(void);
UINT8 *M_ChallengeGridExtraData(void);
#define CHE_NONE 0
#define CHE_HINT 1
#define CHE_DONTDRAW 2
#define CHE_NONE 0
#define CHE_HINT 1
#define CHE_CONNECTEDLEFT 2
#define CHE_CONNECTEDUP 4
#define CHE_DONTDRAW (CHE_CONNECTEDLEFT|CHE_CONNECTEDUP)
// Condition set setup
void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2);