mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
All courses are restricted in Match Race/Time Attack/Online if not visited in GP UNLESS:
- It is the first Race Course of a Cup
- Course has "NoVisitNeeded = True`
- The Controls Tutorial and Test Run are the only two stages that will need this
The above replaces:
- A lot of restricted courses having to be marked with `FinishNeeded = True`
- Hidden Palace
- Sealed Stars 1-14
- Once Special Mode is unlocked, it will now be possible to practice Sealed Stars before rematching them in GP
- Almost all Tutorial-specific behaviour, since it was heinously hacky
HOWEVER, `FinishNeeded = True` was left in specifically for future releases, and I reserve the right to use it on Adventure Example again before launch.
345 lines
6.8 KiB
C
345 lines
6.8 KiB
C
/// \file menus/extras-challenges.c
|
|
/// \brief Statistics menu
|
|
|
|
#include "../k_menu.h"
|
|
#include "../z_zone.h"
|
|
#include "../m_cond.h" // Condition Sets
|
|
#include "../s_sound.h"
|
|
#include "../r_skins.h"
|
|
|
|
struct statisticsmenu_s statisticsmenu;
|
|
|
|
static boolean M_StatisticsAddMap(UINT16 map, cupheader_t *cup, boolean *headerexists, boolean tutorial)
|
|
{
|
|
if (!mapheaderinfo[map])
|
|
return false;
|
|
|
|
if (mapheaderinfo[map]->cup != cup)
|
|
return false;
|
|
|
|
if (((mapheaderinfo[map]->typeoflevel & TOL_TUTORIAL) == TOL_TUTORIAL) != tutorial)
|
|
return false;
|
|
|
|
// Check for no visibility
|
|
if (mapheaderinfo[map]->menuflags & LF2_HIDEINMENU)
|
|
return false;
|
|
|
|
// Check for visitation
|
|
// (M_CanShowLevelInList also checks being the first map in a cup,
|
|
// but we don't need to do this here because it'd just muddy stats!)
|
|
if (!(mapheaderinfo[map]->menuflags & LF2_NOVISITNEEDED)
|
|
&& !(mapheaderinfo[map]->records.mapvisited & MV_VISITED))
|
|
return false;
|
|
|
|
#if 0
|
|
// Check for completion
|
|
if ((mapheaderinfo[map]->menuflags & LF2_FINISHNEEDED)
|
|
&& !(mapheaderinfo[map]->records.mapvisited & MV_BEATEN))
|
|
return false;
|
|
#endif
|
|
|
|
// Check for unlock
|
|
if (M_MapLocked(map+1))
|
|
return false;
|
|
|
|
if (*headerexists == false)
|
|
{
|
|
statisticsmenu.maplist[statisticsmenu.nummaps++] = NEXTMAP_TITLE; // cheeky hack
|
|
*headerexists = true;
|
|
}
|
|
|
|
statisticsmenu.maplist[statisticsmenu.nummaps++] = map;
|
|
return true;
|
|
}
|
|
|
|
static void M_StatisticsMaps(void)
|
|
{
|
|
cupheader_t *cup;
|
|
UINT16 i;
|
|
boolean headerexists;
|
|
|
|
statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (nummapheaders+1 + numkartcupheaders), PU_STATIC, NULL);
|
|
statisticsmenu.nummaps = 0;
|
|
|
|
// Cups
|
|
for (cup = kartcupheaders; cup; cup = cup->next)
|
|
{
|
|
headerexists = false;
|
|
|
|
if (M_CupLocked(cup))
|
|
continue;
|
|
|
|
for (i = 0; i < CUPCACHE_PODIUM; i++)
|
|
{
|
|
if (cup->cachedlevels[i] >= nummapheaders)
|
|
continue;
|
|
|
|
M_StatisticsAddMap(cup->cachedlevels[i], cup, &headerexists, false);
|
|
}
|
|
}
|
|
|
|
// Lost and Found
|
|
headerexists = false;
|
|
for (i = 0; i < nummapheaders; i++)
|
|
{
|
|
M_StatisticsAddMap(i, NULL, &headerexists, false);
|
|
}
|
|
|
|
// Tutorial
|
|
headerexists = false;
|
|
for (i = 0; i < nummapheaders; i++)
|
|
{
|
|
M_StatisticsAddMap(i, NULL, &headerexists, true);
|
|
}
|
|
|
|
if ((i = statisticsmenu.numextramedals) != 0)
|
|
i += 2;
|
|
|
|
statisticsmenu.maplist[statisticsmenu.nummaps] = NEXTMAP_INVALID;
|
|
statisticsmenu.maxscroll = (statisticsmenu.nummaps + i) - 12;
|
|
statisticsmenu.location = 0;
|
|
|
|
if (statisticsmenu.maxscroll < 0)
|
|
{
|
|
statisticsmenu.maxscroll = 0;
|
|
}
|
|
}
|
|
|
|
static void M_StatisticsChars(void)
|
|
{
|
|
UINT16 i;
|
|
|
|
statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (1 + numskins), PU_STATIC, NULL);
|
|
statisticsmenu.nummaps = 0;
|
|
|
|
UINT32 beststat = 0;
|
|
|
|
for (i = 0; i < numskins; i++)
|
|
{
|
|
if (!R_SkinUsable(-1, i, false))
|
|
continue;
|
|
|
|
statisticsmenu.maplist[statisticsmenu.nummaps++] = i;
|
|
|
|
if (skins[i].records.wins == 0)
|
|
continue;
|
|
|
|
// The following is a partial duplication of R_GetEngineClass
|
|
{
|
|
if (skins[i].flags & SF_IRONMAN)
|
|
continue; // does not add to any engine class
|
|
|
|
INT32 s = (skins[i].kartspeed - 1);
|
|
INT32 w = (skins[i].kartweight - 1);
|
|
|
|
#define LOCKSTAT(stat) \
|
|
if (stat < 0) { continue; } \
|
|
if (stat > 8) { continue; }
|
|
LOCKSTAT(s);
|
|
LOCKSTAT(w);
|
|
#undef LOCKSTAT
|
|
|
|
if (
|
|
statisticsmenu.statgridplayed[s][w] > skins[i].records.wins
|
|
&& (UINT32_MAX - statisticsmenu.statgridplayed[s][w]) < skins[i].records.wins
|
|
)
|
|
continue; // overflow protection
|
|
|
|
statisticsmenu.statgridplayed[s][w] += skins[i].records.wins;
|
|
|
|
if (beststat >= statisticsmenu.statgridplayed[s][w])
|
|
continue;
|
|
|
|
beststat = statisticsmenu.statgridplayed[s][w];
|
|
}
|
|
}
|
|
|
|
statisticsmenu.maplist[statisticsmenu.nummaps] = MAXSKINS;
|
|
|
|
statisticsmenu.location = 0;
|
|
statisticsmenu.maxscroll = statisticsmenu.nummaps - 6;
|
|
|
|
if (statisticsmenu.maxscroll < 0)
|
|
{
|
|
statisticsmenu.maxscroll = 0;
|
|
}
|
|
|
|
if (beststat != 0)
|
|
{
|
|
UINT16 j;
|
|
UINT8 shif = 0;
|
|
|
|
// Done this way to ensure ample precision but also prevent overflow
|
|
while (beststat < FRACUNIT)
|
|
{
|
|
beststat <<= 1;
|
|
shif++;
|
|
}
|
|
|
|
for (i = 0; i < 9; i++)
|
|
{
|
|
for (j = 0; j < 9; j++)
|
|
{
|
|
if (statisticsmenu.statgridplayed[i][j] == 0)
|
|
continue;
|
|
|
|
statisticsmenu.statgridplayed[i][j] =
|
|
FixedDiv(
|
|
statisticsmenu.statgridplayed[i][j] << shif,
|
|
beststat
|
|
);
|
|
|
|
if (statisticsmenu.statgridplayed[i][j] == 0)
|
|
statisticsmenu.statgridplayed[i][j] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void M_StatisticsGP(void)
|
|
{
|
|
statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (1 + numkartcupheaders), PU_STATIC, NULL);
|
|
statisticsmenu.nummaps = 0;
|
|
|
|
cupheader_t *cup;
|
|
|
|
for (cup = kartcupheaders; cup; cup = cup->next)
|
|
{
|
|
if (M_CupLocked(cup))
|
|
continue;
|
|
|
|
statisticsmenu.maplist[statisticsmenu.nummaps++] = cup->id;
|
|
}
|
|
|
|
statisticsmenu.maplist[statisticsmenu.nummaps] = UINT16_MAX;
|
|
|
|
statisticsmenu.location = 0;
|
|
statisticsmenu.maxscroll = statisticsmenu.nummaps - 5;
|
|
|
|
if (statisticsmenu.maxscroll < 0)
|
|
{
|
|
statisticsmenu.maxscroll = 0;
|
|
}
|
|
}
|
|
|
|
static void M_StatisticsPageInit(void)
|
|
{
|
|
switch (statisticsmenu.page)
|
|
{
|
|
case statisticspage_maps:
|
|
{
|
|
M_StatisticsMaps();
|
|
break;
|
|
}
|
|
|
|
case statisticspage_chars:
|
|
{
|
|
M_StatisticsChars();
|
|
break;
|
|
}
|
|
|
|
case statisticspage_gp:
|
|
{
|
|
M_StatisticsGP();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void M_StatisticsPageClear(void)
|
|
{
|
|
if (statisticsmenu.maplist != NULL)
|
|
{
|
|
Z_Free(statisticsmenu.maplist);
|
|
statisticsmenu.maplist = NULL;
|
|
}
|
|
}
|
|
|
|
void M_Statistics(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
|
|
statisticsmenu.gotmedals = M_CountMedals(false, false);
|
|
statisticsmenu.nummedals = M_CountMedals(true, false);
|
|
statisticsmenu.numextramedals = M_CountMedals(true, true);
|
|
|
|
M_StatisticsPageInit();
|
|
|
|
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);
|
|
|
|
M_StatisticsPageClear();
|
|
|
|
return true;
|
|
}
|
|
|
|
if (menucmd[pid].dpad_lr != 0)
|
|
{
|
|
M_StatisticsPageClear();
|
|
|
|
statisticsmenu.page +=
|
|
statisticspage_max
|
|
+ (
|
|
(menucmd[pid].dpad_lr > 0)
|
|
? 1
|
|
: -1
|
|
);
|
|
|
|
statisticsmenu.page %= statisticspage_max;
|
|
|
|
M_StatisticsPageInit();
|
|
|
|
S_StartSound(NULL, sfx_s3k5b);
|
|
M_SetMenuDelay(pid);
|
|
|
|
return true;
|
|
}
|
|
|
|
if (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;
|
|
}
|