mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Add "Characters & Emgine Classes" page to statistics
- Shows wins for every character
- Shows heatmap of which stats are your favourite (of the loaded skins)
- Adds a header to the top of all statistics pages showing you can scroll left and right
- General spacing is adjusted to accomodate
This commit is contained in:
parent
52b4104f86
commit
9ed1471c95
3 changed files with 270 additions and 35 deletions
|
|
@ -1263,6 +1263,7 @@ typedef enum
|
||||||
{
|
{
|
||||||
statisticspage_basic = 0,
|
statisticspage_basic = 0,
|
||||||
statisticspage_maps,
|
statisticspage_maps,
|
||||||
|
statisticspage_chars,
|
||||||
statisticspage_max
|
statisticspage_max
|
||||||
} statisticspage_t;
|
} statisticspage_t;
|
||||||
|
|
||||||
|
|
@ -1273,6 +1274,7 @@ extern struct statisticsmenu_s {
|
||||||
INT32 gotmedals;
|
INT32 gotmedals;
|
||||||
INT32 nummedals;
|
INT32 nummedals;
|
||||||
INT32 numextramedals;
|
INT32 numextramedals;
|
||||||
|
UINT32 statgridplayed[9][9];
|
||||||
INT32 maxscroll;
|
INT32 maxscroll;
|
||||||
UINT16 *maplist;
|
UINT16 *maplist;
|
||||||
} statisticsmenu;
|
} statisticsmenu;
|
||||||
|
|
|
||||||
179
src/k_menudraw.c
179
src/k_menudraw.c
|
|
@ -6180,6 +6180,120 @@ bottomarrow:
|
||||||
'\x1B' | highlightflags, false); // down arrow
|
'\x1B' | highlightflags, false); // down arrow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef STATSSTEP
|
||||||
|
#define STATSSTEP 18
|
||||||
|
|
||||||
|
static void M_DrawStatsChars(void)
|
||||||
|
{
|
||||||
|
INT32 y = 80, i, j;
|
||||||
|
INT16 skin;
|
||||||
|
boolean dobottomarrow = (statisticsmenu.location < statisticsmenu.maxscroll);
|
||||||
|
INT32 location = statisticsmenu.location;
|
||||||
|
|
||||||
|
if (!statisticsmenu.maplist)
|
||||||
|
{
|
||||||
|
V_DrawCenteredThinString(BASEVIDWIDTH/2, 62, 0, "No chars!?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location)
|
||||||
|
V_DrawCharacter(10, y-(skullAnimCounter/5),
|
||||||
|
'\x1A' | highlightflags, false); // up arrow
|
||||||
|
|
||||||
|
i = -1;
|
||||||
|
|
||||||
|
V_DrawThinString(20, y - 10, highlightflags, "CHARACTER");
|
||||||
|
V_DrawRightAlignedThinString(BASEVIDWIDTH/2 + 34, y - 10, highlightflags, "WINS");
|
||||||
|
|
||||||
|
while ((skin = statisticsmenu.maplist[++i]) != NEXTMAP_INVALID)
|
||||||
|
{
|
||||||
|
if (location)
|
||||||
|
{
|
||||||
|
--location;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
UINT8 *colormap = R_GetTranslationColormap(skin, skins[skin].prefcolor, GTC_MENUCACHE);
|
||||||
|
|
||||||
|
V_DrawFixedPatch(24*FRACUNIT, y*FRACUNIT,
|
||||||
|
FRACUNIT,
|
||||||
|
0, faceprefix[skin][FACE_RANK],
|
||||||
|
colormap);
|
||||||
|
|
||||||
|
V_DrawFadeFill(24+16, y, 16, 16, 0, 31, 8); // challengetransparentstrength
|
||||||
|
|
||||||
|
V_DrawFill(24+16+5, y+1, 1, 14, 0);
|
||||||
|
V_DrawFill(24+16+5+5, y+1, 1, 14, 0);
|
||||||
|
V_DrawFill(24+16+1, y+5, 14, 1, 0);
|
||||||
|
V_DrawFill(24+16+1, y+5+5, 14, 1, 0);
|
||||||
|
|
||||||
|
// The following is a partial duplication of R_GetEngineClass
|
||||||
|
{
|
||||||
|
INT32 s = (skins[skin].kartspeed - 1)/3;
|
||||||
|
INT32 w = (skins[skin].kartweight - 1)/3;
|
||||||
|
|
||||||
|
#define LOCKSTAT(stat) \
|
||||||
|
if (stat < 0) { stat = 0; } \
|
||||||
|
if (stat > 2) { stat = 2; }
|
||||||
|
LOCKSTAT(s);
|
||||||
|
LOCKSTAT(w);
|
||||||
|
#undef LOCKSTAT
|
||||||
|
|
||||||
|
V_DrawFill(24+16 + (s*5), y + (w*5), 6, 6, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
V_DrawThinString(24+32+2, y+3, 0, skins[skin].realname);
|
||||||
|
|
||||||
|
V_DrawRightAlignedThinString(BASEVIDWIDTH/2 + 30, y+3, 0, va("%d", skins[skin].records.wins));
|
||||||
|
|
||||||
|
y += STATSSTEP;
|
||||||
|
|
||||||
|
if (y >= BASEVIDHEIGHT-STATSSTEP)
|
||||||
|
goto bottomarrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomarrow:
|
||||||
|
if (dobottomarrow)
|
||||||
|
V_DrawCharacter(10, y-10 + (skullAnimCounter/5),
|
||||||
|
'\x1B' | highlightflags, false); // down arrow
|
||||||
|
|
||||||
|
UINT32 x = BASEVIDWIDTH - 20 - 90;
|
||||||
|
y = 88;
|
||||||
|
|
||||||
|
V_DrawCenteredThinString(x + 45, y - 10, highlightflags, "HEATMAP");
|
||||||
|
|
||||||
|
V_DrawFadeFill(x, y, 91, 91, 0, 31, 8); // challengetransparentstrength
|
||||||
|
|
||||||
|
V_DrawFill(x+30, y+1, 1, 89, 0);
|
||||||
|
V_DrawFill(x+60, y+1, 1, 89, 0);
|
||||||
|
V_DrawFill(x+1, y+30, 89, 1, 0);
|
||||||
|
V_DrawFill(x+1, y+60, 89, 1, 0);
|
||||||
|
|
||||||
|
x++;
|
||||||
|
y++;
|
||||||
|
|
||||||
|
for (i = 0; i < 9; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 9; j++)
|
||||||
|
{
|
||||||
|
if (statisticsmenu.statgridplayed[i][j] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
V_DrawFill(
|
||||||
|
x + (i * 10),
|
||||||
|
y + (j * 10),
|
||||||
|
9,
|
||||||
|
9,
|
||||||
|
31 - ((statisticsmenu.statgridplayed[i][j] - 1) * 32) / FRACUNIT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef STATSSTEP
|
||||||
|
|
||||||
void M_DrawStatistics(void)
|
void M_DrawStatistics(void)
|
||||||
{
|
{
|
||||||
char beststr[256];
|
char beststr[256];
|
||||||
|
|
@ -6190,8 +6304,47 @@ void M_DrawStatistics(void)
|
||||||
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
|
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *pagename = NULL;
|
||||||
|
INT32 pagenamewidth = 0;
|
||||||
|
|
||||||
|
V_DrawFixedPatch(0, 0, FRACUNIT, 0, W_CachePatchName("MENUHINT", PU_CACHE), NULL);
|
||||||
|
|
||||||
|
switch (statisticsmenu.page)
|
||||||
|
{
|
||||||
|
case statisticspage_maps:
|
||||||
|
{
|
||||||
|
pagename = "LEVELS & MEDALS";
|
||||||
|
M_DrawStatsMaps();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case statisticspage_chars:
|
||||||
|
{
|
||||||
|
pagename = "CHARACTERS & ENGINE CLASSES";
|
||||||
|
M_DrawStatsChars();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pagename)
|
||||||
|
{
|
||||||
|
pagenamewidth = V_ThinStringWidth(pagename, 0);
|
||||||
|
V_DrawThinString((BASEVIDWIDTH - pagenamewidth)/2, 12, 0, pagename);
|
||||||
|
}
|
||||||
|
|
||||||
|
V_DrawCharacter((BASEVIDWIDTH - pagenamewidth)/2 - 10 - (skullAnimCounter/5), 12,
|
||||||
|
'\x1C', false); // left arrow
|
||||||
|
|
||||||
|
V_DrawCharacter((BASEVIDWIDTH + pagenamewidth)/2 + 2 + (skullAnimCounter/5), 12,
|
||||||
|
'\x1D', false); // right arrow
|
||||||
|
}
|
||||||
|
|
||||||
beststr[0] = 0;
|
beststr[0] = 0;
|
||||||
V_DrawThinString(20, 22, highlightflags, "Total Play Time:");
|
V_DrawThinString(20, 30, highlightflags, "Total Play Time:");
|
||||||
besttime = G_TicsToHours(gamedata->totalplaytime);
|
besttime = G_TicsToHours(gamedata->totalplaytime);
|
||||||
if (besttime)
|
if (besttime)
|
||||||
{
|
{
|
||||||
|
|
@ -6210,10 +6363,10 @@ void M_DrawStatistics(void)
|
||||||
}
|
}
|
||||||
besttime = G_TicsToSeconds(gamedata->totalplaytime);
|
besttime = G_TicsToSeconds(gamedata->totalplaytime);
|
||||||
strcat(beststr, va("%i second%s", besttime, (besttime == 1 ? "" : "s")));
|
strcat(beststr, va("%i second%s", besttime, (besttime == 1 ? "" : "s")));
|
||||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 22, 0, beststr);
|
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 30, 0, beststr);
|
||||||
beststr[0] = 0;
|
beststr[0] = 0;
|
||||||
|
|
||||||
V_DrawThinString(20, 32, highlightflags, "Total Rings:");
|
V_DrawThinString(20, 40, highlightflags, "Total Rings:");
|
||||||
if (gamedata->totalrings > GDMAX_RINGS)
|
if (gamedata->totalrings > GDMAX_RINGS)
|
||||||
{
|
{
|
||||||
sprintf(beststr, "%c999,999,999+", '\x82');
|
sprintf(beststr, "%c999,999,999+", '\x82');
|
||||||
|
|
@ -6230,10 +6383,10 @@ void M_DrawStatistics(void)
|
||||||
{
|
{
|
||||||
sprintf(beststr, "%u", gamedata->totalrings);
|
sprintf(beststr, "%u", gamedata->totalrings);
|
||||||
}
|
}
|
||||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 32, 0, va("%s collected", beststr));
|
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 40, 0, va("%s collected", beststr));
|
||||||
|
|
||||||
beststr[0] = 0;
|
beststr[0] = 0;
|
||||||
V_DrawThinString(20, 42, highlightflags, "Total Rounds:");
|
V_DrawThinString(20, 50, highlightflags, "Total Rounds:");
|
||||||
|
|
||||||
strcat(beststr, va("%u Race", gamedata->roundsplayed[GDGT_RACE]));
|
strcat(beststr, va("%u Race", gamedata->roundsplayed[GDGT_RACE]));
|
||||||
|
|
||||||
|
|
@ -6254,23 +6407,9 @@ void M_DrawStatistics(void)
|
||||||
strcat(beststr, va(", %u Custom", gamedata->roundsplayed[GDGT_CUSTOM]));
|
strcat(beststr, va(", %u Custom", gamedata->roundsplayed[GDGT_CUSTOM]));
|
||||||
}
|
}
|
||||||
|
|
||||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 42, 0, beststr);
|
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 50, 0, beststr);
|
||||||
|
|
||||||
switch (statisticsmenu.page)
|
|
||||||
{
|
|
||||||
case statisticspage_maps:
|
|
||||||
{
|
|
||||||
M_DrawStatsMaps();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef STATSSTEP
|
|
||||||
|
|
||||||
static INT32 M_WrongWarpFallingHelper(INT32 y, INT32 falltime)
|
static INT32 M_WrongWarpFallingHelper(INT32 y, INT32 falltime)
|
||||||
{
|
{
|
||||||
if (wrongwarp.ticker < falltime)
|
if (wrongwarp.ticker < falltime)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "../z_zone.h"
|
#include "../z_zone.h"
|
||||||
#include "../m_cond.h" // Condition Sets
|
#include "../m_cond.h" // Condition Sets
|
||||||
#include "../s_sound.h"
|
#include "../s_sound.h"
|
||||||
|
#include "../r_skins.h"
|
||||||
|
|
||||||
struct statisticsmenu_s statisticsmenu;
|
struct statisticsmenu_s statisticsmenu;
|
||||||
|
|
||||||
|
|
@ -88,6 +89,97 @@ static void M_StatisticsMaps(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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] = NEXTMAP_INVALID;
|
||||||
|
|
||||||
|
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_StatisticsPageInit(void)
|
static void M_StatisticsPageInit(void)
|
||||||
{
|
{
|
||||||
switch (statisticsmenu.page)
|
switch (statisticsmenu.page)
|
||||||
|
|
@ -98,20 +190,9 @@ static void M_StatisticsPageInit(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
case statisticspage_chars:
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void M_StatisticsPageClear(void)
|
|
||||||
{
|
|
||||||
switch (statisticsmenu.page)
|
|
||||||
{
|
|
||||||
case statisticspage_maps:
|
|
||||||
{
|
{
|
||||||
Z_Free(statisticsmenu.maplist);
|
M_StatisticsChars();
|
||||||
statisticsmenu.maplist = NULL;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,10 +201,23 @@ static void M_StatisticsPageClear(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void M_StatisticsPageClear(void)
|
||||||
|
{
|
||||||
|
if (statisticsmenu.maplist != NULL)
|
||||||
|
{
|
||||||
|
Z_Free(statisticsmenu.maplist);
|
||||||
|
statisticsmenu.maplist = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void M_Statistics(INT32 choice)
|
void M_Statistics(INT32 choice)
|
||||||
{
|
{
|
||||||
(void)choice;
|
(void)choice;
|
||||||
|
|
||||||
|
statisticsmenu.gotmedals = M_CountMedals(false, false);
|
||||||
|
statisticsmenu.nummedals = M_CountMedals(true, false);
|
||||||
|
statisticsmenu.numextramedals = M_CountMedals(true, true);
|
||||||
|
|
||||||
statisticsmenu.page = statisticspage_basic;
|
statisticsmenu.page = statisticspage_basic;
|
||||||
M_StatisticsPageInit();
|
M_StatisticsPageInit();
|
||||||
|
|
||||||
|
|
@ -169,8 +263,8 @@ boolean M_StatisticsInputs(INT32 ch)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statisticsmenu.page != statisticspage_maps)
|
if (statisticsmenu.maplist == NULL)
|
||||||
return true; // temporary
|
return true;
|
||||||
|
|
||||||
if (M_MenuExtraPressed(pid))
|
if (M_MenuExtraPressed(pid))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue