Statistics menu

Relatively quick port from v1., but with under-the-hood changes to match the Emblem/Medal and Extra Medal reworks. We can make it prettier (and contain more data) later.
This commit is contained in:
toaster 2022-12-14 17:53:35 +00:00
parent 2fbbe52ded
commit 42f4f28e06
6 changed files with 362 additions and 16 deletions

View file

@ -405,8 +405,9 @@ extern menu_t MISC_ManualDef;
extern menuitem_t MISC_Addons[];
extern menu_t MISC_AddonsDef;
extern menuitem_t MISC_Challenges[];
extern menuitem_t MISC_ChallengesStatsDummyMenu[];
extern menu_t MISC_ChallengesDef;
extern menu_t MISC_StatisticsDef;
// We'll need this since we're gonna have to dynamically enable and disable options depending on which state we're in.
typedef enum
@ -1124,6 +1125,17 @@ void M_DrawChallenges(void);
void M_ChallengesTick(void);
boolean M_ChallengesInputs(INT32 ch);
extern struct statisticsmenu_s {
INT32 location;
INT32 nummaps;
INT32 maxscroll;
UINT16 *maplist;
} statisticsmenu;
void M_Statistics(INT32 choice);
void M_DrawStatistics(void);
boolean M_StatisticsInputs(INT32 ch);
// These defines make it a little easier to make menus
#define DEFAULTMENUSTYLE(source, prev, x, y)\
{\

View file

@ -1503,7 +1503,7 @@ menuitem_t EXTRAS_Main[] =
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},
NULL, {.routine = M_Statistics}, 0, 0},
};
// the extras menu essentially reuses the options menu stuff
@ -1746,16 +1746,16 @@ menu_t MISC_AddonsDef = {
};
// Challenges.
menuitem_t MISC_ChallengesMenu[] =
menuitem_t MISC_ChallengesStatsDummyMenu[] =
{
{IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0},
};
menu_t MISC_ChallengesDef = {
sizeof (MISC_ChallengesMenu)/sizeof (menuitem_t),
sizeof (MISC_ChallengesStatsDummyMenu)/sizeof (menuitem_t),
&MainDef,
0,
MISC_ChallengesMenu,
MISC_ChallengesStatsDummyMenu,
BASEVIDWIDTH/2, 32,
0, 0,
98, 0,
@ -1765,3 +1765,18 @@ menu_t MISC_ChallengesDef = {
NULL,
M_ChallengesInputs,
};
menu_t MISC_StatisticsDef = {
sizeof (MISC_ChallengesStatsDummyMenu)/sizeof (menuitem_t),
&MainDef,
0,
MISC_ChallengesStatsDummyMenu,
280, 185,
0, 0,
98, 0,
M_DrawStatistics,
NULL,
NULL,
NULL,
M_StatisticsInputs,
};

View file

@ -4461,6 +4461,8 @@ void M_DrawAddons(void)
#undef addonsseperation
// Challenges Menu
#define challengesbordercolor 27
static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili)
@ -4894,3 +4896,228 @@ challengedesc:
V_DrawCenteredString(BASEVIDWIDTH/2, 120 + 32, V_ALLOWLOWERCASE, challengesmenu.unlockcondition);
}
}
// Statistics menu
#define STATSSTEP 10
static void M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y)
{
UINT8 lasttype = UINT8_MAX, curtype;
emblem_t *emblem = M_GetLevelEmblems(mapnum);
while (emblem)
{
switch (emblem->type)
{
case ET_TIME:
curtype = 1;
break;
case ET_GLOBAL:
{
if (emblem->flags & GE_NOTMEDAL)
{
emblem = M_GetLevelEmblems(-1);
continue;
}
curtype = 2;
break;
}
default:
curtype = 0;
break;
}
// Shift over if emblem is of a different discipline
if (lasttype != UINT8_MAX && lasttype != curtype)
x -= 4;
lasttype = curtype;
if (gamedata->collected[emblem-emblemlocations])
V_DrawSmallMappedPatch(x, y, 0, W_CachePatchName(M_GetEmblemPatch(emblem, false), PU_CACHE),
R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_MENUCACHE));
else
V_DrawSmallScaledPatch(x, y, 0, W_CachePatchName("NEEDIT", PU_CACHE));
emblem = M_GetLevelEmblems(-1);
x -= 8;
}
}
static void M_DrawStatsMaps(void)
{
INT32 y = 80, i = -1;
INT16 mnum;
boolean dotopname = true, dobottomarrow = (statisticsmenu.location < statisticsmenu.maxscroll);
INT32 location = statisticsmenu.location;
if (location)
V_DrawCharacter(10, y-(skullAnimCounter/5),
'\x1A' | highlightflags, false); // up arrow
while (statisticsmenu.maplist[++i] != NEXTMAP_INVALID)
{
if (location)
{
--location;
continue;
}
else if (dotopname)
{
V_DrawThinString(20, y, highlightflags, "LEVEL NAME");
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, y, highlightflags, "MEDALS");
y += STATSSTEP;
dotopname = false;
}
mnum = statisticsmenu.maplist[i]+1;
M_DrawMapMedals(mnum, 291, y);
{
char *title = G_BuildMapTitle(mnum);
V_DrawThinString(20, y, 0, title);
Z_Free(title);
}
y += STATSSTEP;
if (y >= BASEVIDHEIGHT-STATSSTEP)
goto bottomarrow;
}
if (dotopname && !location)
{
V_DrawString(20, y, highlightflags, "LEVEL NAME");
V_DrawString(256, y, highlightflags, "MEDALS");
y += STATSSTEP;
}
else if (location)
--location;
// Extra Emblem headers
for (i = 0; i < 2; ++i)
{
if (i == 1)
{
V_DrawThinString(20, y, highlightflags, "EXTRA MEDALS");
if (location)
{
y += STATSSTEP;
location++;
}
}
if (location)
{
--location;
continue;
}
y += STATSSTEP;
if (y >= BASEVIDHEIGHT-STATSSTEP)
goto bottomarrow;
}
// Extra Emblems
for (i = 0; i < MAXUNLOCKABLES; i++)
{
if (unlockables[i].type != SECRET_EXTRAMEDAL)
{
continue;
}
if (location)
{
--location;
continue;
}
if (i >= 0)
{
if (gamedata->unlocked[i])
{
UINT16 color = min(unlockables[i].color, numskincolors-1);
if (!color)
color = SKINCOLOR_GOLD;
V_DrawSmallMappedPatch(291, y+1, 0, W_CachePatchName("GOTITA", PU_CACHE),
R_GetTranslationColormap(TC_DEFAULT, color, GTC_MENUCACHE));
}
else
{
V_DrawSmallScaledPatch(291, y+1, 0, W_CachePatchName("NEEDIT", PU_CACHE));
}
V_DrawThinString(20, y, 0, va("%s", unlockables[i].name));
}
y += STATSSTEP;
if (y >= BASEVIDHEIGHT-STATSSTEP)
goto bottomarrow;
}
bottomarrow:
if (dobottomarrow)
V_DrawCharacter(10, y-STATSSTEP + (skullAnimCounter/5),
'\x1B' | highlightflags, false); // down arrow
}
void M_DrawStatistics(void)
{
char beststr[40];
tic_t besttime = 0;
INT32 i;
INT32 mapsunfinished = 0;
{
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
}
V_DrawThinString(20, 22, V_ALLOWLOWERCASE|highlightflags, "Total Play Time:");
V_DrawCenteredThinString(BASEVIDWIDTH/2, 32, 0,
va("%i hours, %i minutes, %i seconds",
G_TicsToHours(gamedata->totalplaytime),
G_TicsToMinutes(gamedata->totalplaytime, false),
G_TicsToSeconds(gamedata->totalplaytime)));
V_DrawThinString(20, 42, V_ALLOWLOWERCASE|highlightflags, "Total Matches:");
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 42, 0, va("%i played", gamedata->matchesplayed));
if (!statisticsmenu.maplist)
{
V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, V_ALLOWLOWERCASE, "No maps!?");
return;
}
for (i = 0; i < nummapheaders; i++)
{
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU)))
continue;
if (!mapheaderinfo[i]->mainrecord || mapheaderinfo[i]->mainrecord->time <= 0)
{
mapsunfinished++;
continue;
}
besttime += mapheaderinfo[i]->mainrecord->time;
}
V_DrawThinString(20, 60, V_ALLOWLOWERCASE, "Combined time records:");
sprintf(beststr, "%i:%02i:%02i.%02i", G_TicsToHours(besttime), G_TicsToMinutes(besttime, false), G_TicsToSeconds(besttime), G_TicsToCentiseconds(besttime));
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 60, V_ALLOWLOWERCASE|(mapsunfinished ? V_REDMAP : 0), beststr);
if (mapsunfinished)
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, V_ALLOWLOWERCASE|V_REDMAP, va("(%d unfinished)", mapsunfinished));
else
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 70, V_ALLOWLOWERCASE, "(complete)");
V_DrawThinString(32, 70, 0, va("x %d/%d", M_CountMedals(false, false), M_CountMedals(true, false)));
V_DrawSmallMappedPatch(20, 70, 0, W_CachePatchName("GOTITA", PU_CACHE),
R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_GOLD, GTC_MENUCACHE));
M_DrawStatsMaps();
}
#undef STATSSTEP

View file

@ -6853,6 +6853,8 @@ void M_Manual(INT32 choice)
M_SetupNextMenu(&MISC_ManualDef, true);
}
// Challenges menu
struct challengesmenu_s challengesmenu;
menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
@ -7385,3 +7387,90 @@ boolean M_ChallengesInputs(INT32 ch)
return true;
}
// Statistics menu
struct statisticsmenu_s statisticsmenu;
void M_Statistics(INT32 choice)
{
UINT16 i = 0;
(void)choice;
statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * nummapheaders, PU_STATIC, NULL);
statisticsmenu.nummaps = 0;
for (i = 0; i < nummapheaders; i++)
{
if (!mapheaderinfo[i])
continue;
if (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU))
continue;
if (M_MapLocked(i+1))
continue;
statisticsmenu.maplist[statisticsmenu.nummaps++] = i;
}
statisticsmenu.maplist[statisticsmenu.nummaps] = NEXTMAP_INVALID;
statisticsmenu.maxscroll = (statisticsmenu.nummaps + M_CountMedals(true, true) + 2) - 10;
statisticsmenu.location = 0;
if (statisticsmenu.maxscroll < 0)
{
statisticsmenu.maxscroll = 0;
}
MISC_StatisticsDef.prevMenu = currentMenu;
M_SetupNextMenu(&MISC_StatisticsDef, false);
}
boolean M_StatisticsInputs(INT32 ch)
{
const UINT8 pid = 0;
(void)ch;
if (M_MenuBackPressed(pid))
{
M_GoBack(0);
M_SetMenuDelay(pid);
Z_Free(statisticsmenu.maplist);
statisticsmenu.maplist = NULL;
return true;
}
if (M_MenuExtraPressed(pid))
{
if (statisticsmenu.location > 0)
{
statisticsmenu.location = 0;
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
}
else if (menucmd[pid].dpad_ud > 0)
{
if (statisticsmenu.location < statisticsmenu.maxscroll)
{
statisticsmenu.location++;
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
}
else if (menucmd[pid].dpad_ud < 0)
{
if (statisticsmenu.location > 0)
{
statisticsmenu.location--;
S_StartSound(NULL, sfx_s3k5b);
M_SetMenuDelay(pid);
}
}
return true;
}

View file

@ -1123,17 +1123,20 @@ boolean M_MapLocked(INT32 mapnum)
return false;
}
INT32 M_CountMedals(boolean all)
INT32 M_CountMedals(boolean all, boolean extraonly)
{
INT32 found = 0, i;
for (i = 0; i < numemblems; ++i)
if (!extraonly)
{
if ((emblemlocations[i].type == ET_GLOBAL)
&& (emblemlocations[i].flags & GE_NOTMEDAL))
continue;
if (!all && !gamedata->collected[i])
continue;
found++;
for (i = 0; i < numemblems; ++i)
{
if ((emblemlocations[i].type == ET_GLOBAL)
&& (emblemlocations[i].flags & GE_NOTMEDAL))
continue;
if (!all && !gamedata->collected[i])
continue;
found++;
}
}
for (i = 0; i < MAXUNLOCKABLES; ++i)
{
@ -1404,8 +1407,8 @@ emblem_t *M_GetLevelEmblems(INT32 mapnum)
skincolornum_t M_GetEmblemColor(emblem_t *em)
{
if (!em || em->color >= numskincolors)
return SKINCOLOR_NONE;
if (!em || !em->color || em->color >= numskincolors)
return SKINCOLOR_GOLD;
return em->color;
}

View file

@ -211,7 +211,7 @@ boolean M_CheckNetUnlockByID(UINT8 unlockid);
boolean M_SecretUnlocked(INT32 type, boolean local);
boolean M_CupLocked(cupheader_t *cup);
boolean M_MapLocked(INT32 mapnum);
INT32 M_CountMedals(boolean all);
INT32 M_CountMedals(boolean all, boolean extraonly);
// Emblem shit
emblem_t *M_GetLevelEmblems(INT32 mapnum);