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_maps,
|
||||
statisticspage_chars,
|
||||
statisticspage_max
|
||||
} statisticspage_t;
|
||||
|
||||
|
|
@ -1273,6 +1274,7 @@ extern struct statisticsmenu_s {
|
|||
INT32 gotmedals;
|
||||
INT32 nummedals;
|
||||
INT32 numextramedals;
|
||||
UINT32 statgridplayed[9][9];
|
||||
INT32 maxscroll;
|
||||
UINT16 *maplist;
|
||||
} statisticsmenu;
|
||||
|
|
|
|||
179
src/k_menudraw.c
179
src/k_menudraw.c
|
|
@ -6180,6 +6180,120 @@ bottomarrow:
|
|||
'\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)
|
||||
{
|
||||
char beststr[256];
|
||||
|
|
@ -6190,8 +6304,47 @@ void M_DrawStatistics(void)
|
|||
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;
|
||||
V_DrawThinString(20, 22, highlightflags, "Total Play Time:");
|
||||
V_DrawThinString(20, 30, highlightflags, "Total Play Time:");
|
||||
besttime = G_TicsToHours(gamedata->totalplaytime);
|
||||
if (besttime)
|
||||
{
|
||||
|
|
@ -6210,10 +6363,10 @@ void M_DrawStatistics(void)
|
|||
}
|
||||
besttime = G_TicsToSeconds(gamedata->totalplaytime);
|
||||
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;
|
||||
|
||||
V_DrawThinString(20, 32, highlightflags, "Total Rings:");
|
||||
V_DrawThinString(20, 40, highlightflags, "Total Rings:");
|
||||
if (gamedata->totalrings > GDMAX_RINGS)
|
||||
{
|
||||
sprintf(beststr, "%c999,999,999+", '\x82');
|
||||
|
|
@ -6230,10 +6383,10 @@ void M_DrawStatistics(void)
|
|||
{
|
||||
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;
|
||||
V_DrawThinString(20, 42, highlightflags, "Total Rounds:");
|
||||
V_DrawThinString(20, 50, highlightflags, "Total Rounds:");
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 42, 0, beststr);
|
||||
|
||||
switch (statisticsmenu.page)
|
||||
{
|
||||
case statisticspage_maps:
|
||||
{
|
||||
M_DrawStatsMaps();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 50, 0, beststr);
|
||||
}
|
||||
|
||||
#undef STATSSTEP
|
||||
|
||||
static INT32 M_WrongWarpFallingHelper(INT32 y, INT32 falltime)
|
||||
{
|
||||
if (wrongwarp.ticker < falltime)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "../z_zone.h"
|
||||
#include "../m_cond.h" // Condition Sets
|
||||
#include "../s_sound.h"
|
||||
#include "../r_skins.h"
|
||||
|
||||
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)
|
||||
{
|
||||
switch (statisticsmenu.page)
|
||||
|
|
@ -98,20 +190,9 @@ static void M_StatisticsPageInit(void)
|
|||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void M_StatisticsPageClear(void)
|
||||
{
|
||||
switch (statisticsmenu.page)
|
||||
{
|
||||
case statisticspage_maps:
|
||||
case statisticspage_chars:
|
||||
{
|
||||
Z_Free(statisticsmenu.maplist);
|
||||
statisticsmenu.maplist = NULL;
|
||||
|
||||
M_StatisticsChars();
|
||||
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)choice;
|
||||
|
||||
statisticsmenu.gotmedals = M_CountMedals(false, false);
|
||||
statisticsmenu.nummedals = M_CountMedals(true, false);
|
||||
statisticsmenu.numextramedals = M_CountMedals(true, true);
|
||||
|
||||
statisticsmenu.page = statisticspage_basic;
|
||||
M_StatisticsPageInit();
|
||||
|
||||
|
|
@ -169,8 +263,8 @@ boolean M_StatisticsInputs(INT32 ch)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (statisticsmenu.page != statisticspage_maps)
|
||||
return true; // temporary
|
||||
if (statisticsmenu.maplist == NULL)
|
||||
return true;
|
||||
|
||||
if (M_MenuExtraPressed(pid))
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue