mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-04-19 16:47:00 +00:00
Merge branch 'throw-more-dots' into 'master'
Add a bunch more statistics See merge request KartKrew/Kart!1973
This commit is contained in:
commit
5b466527e8
18 changed files with 493 additions and 57 deletions
|
|
@ -590,6 +590,16 @@ UINT32 quickncasehash (const char *p, size_t n)
|
|||
return x;
|
||||
}
|
||||
|
||||
// m_cond, doomstat
|
||||
typedef enum {
|
||||
GDGT_RACE,
|
||||
GDGT_BATTLE,
|
||||
GDGT_PRISONS,
|
||||
GDGT_SPECIAL,
|
||||
GDGT_CUSTOM,
|
||||
GDGT_MAX
|
||||
} roundsplayed_t;
|
||||
|
||||
#ifndef __cplusplus
|
||||
#ifndef min // Double-Check with WATTCP-32's cdefs.h
|
||||
#define min(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
|
|
|||
|
|
@ -122,6 +122,10 @@ extern preciptype_t curWeather;
|
|||
struct skinrecord_t
|
||||
{
|
||||
UINT32 wins;
|
||||
UINT32 rounds;
|
||||
UINT32 timeplayed;
|
||||
UINT32 modetimeplayed[GDGT_MAX];
|
||||
UINT32 tumbletime;
|
||||
};
|
||||
|
||||
struct unloaded_skin_t
|
||||
|
|
@ -161,6 +165,13 @@ struct recorddata_t
|
|||
UINT8 mapvisited;
|
||||
recordtimes_t timeattack; ///< Best times for Time Attack
|
||||
recordtimes_t spbattack; ///< Best times for SPB Attack
|
||||
UINT32 timeplayed;
|
||||
UINT32 netgametimeplayed;
|
||||
UINT32 modetimeplayed[GDGT_MAX];
|
||||
UINT32 timeattacktimeplayed;
|
||||
UINT32 spbattacktimeplayed;
|
||||
UINT32 rounds;
|
||||
UINT32 wins;
|
||||
};
|
||||
|
||||
#define KARTSPEED_AUTO -1
|
||||
|
|
|
|||
|
|
@ -4516,14 +4516,7 @@ static void G_DoCompleted(void)
|
|||
{
|
||||
if (gametype != GT_TUTORIAL)
|
||||
{
|
||||
UINT8 roundtype = GDGT_CUSTOM;
|
||||
|
||||
if (gametype == GT_RACE)
|
||||
roundtype = GDGT_RACE;
|
||||
else if (gametype == GT_BATTLE)
|
||||
roundtype = (battleprisons ? GDGT_PRISONS : GDGT_BATTLE);
|
||||
else if (gametype == GT_SPECIAL || gametype == GT_VERSUS)
|
||||
roundtype = GDGT_SPECIAL;
|
||||
UINT8 roundtype = M_GameDataGameType(gametype, battleprisons);
|
||||
|
||||
gamedata->roundsplayed[roundtype]++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,16 @@ void srb2::save_ng_gamedata()
|
|||
GamedataJson ng {};
|
||||
|
||||
ng.playtime.total = gamedata->totalplaytime;
|
||||
ng.playtime.netgame = gamedata->totalnetgametime;
|
||||
ng.playtime.timeattack = gamedata->timeattackingtotaltime;
|
||||
ng.playtime.spbattack = gamedata->spbattackingtotaltime;
|
||||
ng.playtime.race = gamedata->modeplaytime[GDGT_RACE];
|
||||
ng.playtime.battle = gamedata->modeplaytime[GDGT_BATTLE];
|
||||
ng.playtime.prisons = gamedata->modeplaytime[GDGT_PRISONS];
|
||||
ng.playtime.special = gamedata->modeplaytime[GDGT_SPECIAL];
|
||||
ng.playtime.custom = gamedata->modeplaytime[GDGT_CUSTOM];
|
||||
ng.playtime.menus = gamedata->totalmenutime;
|
||||
ng.playtime.statistics = gamedata->totaltimestaringatstatistics;
|
||||
ng.rings.total = gamedata->totalrings;
|
||||
ng.playtime.tumble = gamedata->totaltumbletime;
|
||||
ng.rounds.race = gamedata->roundsplayed[GDGT_RACE];
|
||||
|
|
@ -103,8 +113,18 @@ void srb2::save_ng_gamedata()
|
|||
for (int i = 0; i < numskins; i++)
|
||||
{
|
||||
srb2::GamedataSkinJson skin {};
|
||||
std::string name = std::string(skins[i].name);
|
||||
skin.records.wins = skins[i].records.wins;
|
||||
skin_t& memskin = skins[i];
|
||||
|
||||
std::string name = std::string(memskin.name);
|
||||
skin.records.wins = memskin.records.wins;
|
||||
skin.records.rounds = memskin.records.rounds;
|
||||
skin.records.time.total = memskin.records.timeplayed;
|
||||
skin.records.time.race = memskin.records.modetimeplayed[GDGT_RACE];
|
||||
skin.records.time.battle = memskin.records.modetimeplayed[GDGT_BATTLE];
|
||||
skin.records.time.prisons = memskin.records.modetimeplayed[GDGT_PRISONS];
|
||||
skin.records.time.special = memskin.records.modetimeplayed[GDGT_SPECIAL];
|
||||
skin.records.time.custom = memskin.records.modetimeplayed[GDGT_CUSTOM];
|
||||
skin.records.time.tumble = memskin.records.tumbletime;
|
||||
ng.skins[name] = std::move(skin);
|
||||
}
|
||||
for (auto unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next)
|
||||
|
|
@ -127,6 +147,15 @@ void srb2::save_ng_gamedata()
|
|||
map.stats.timeattack.bestlap = mapheaderinfo[i]->records.timeattack.lap;
|
||||
map.stats.spbattack.besttime = mapheaderinfo[i]->records.spbattack.time;
|
||||
map.stats.spbattack.bestlap = mapheaderinfo[i]->records.spbattack.lap;
|
||||
map.stats.time.total = mapheaderinfo[i]->records.timeplayed;
|
||||
map.stats.time.netgame = mapheaderinfo[i]->records.netgametimeplayed;
|
||||
map.stats.time.race = mapheaderinfo[i]->records.modetimeplayed[GDGT_RACE];
|
||||
map.stats.time.battle = mapheaderinfo[i]->records.modetimeplayed[GDGT_BATTLE];
|
||||
map.stats.time.prisons = mapheaderinfo[i]->records.modetimeplayed[GDGT_PRISONS];
|
||||
map.stats.time.special = mapheaderinfo[i]->records.modetimeplayed[GDGT_SPECIAL];
|
||||
map.stats.time.custom = mapheaderinfo[i]->records.modetimeplayed[GDGT_CUSTOM];
|
||||
map.stats.time.timeattack = mapheaderinfo[i]->records.timeattacktimeplayed;
|
||||
map.stats.time.spbattack = mapheaderinfo[i]->records.spbattacktimeplayed;
|
||||
ng.maps[lumpname] = std::move(map);
|
||||
}
|
||||
for (auto unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = unloadedmap->next)
|
||||
|
|
@ -142,6 +171,15 @@ void srb2::save_ng_gamedata()
|
|||
map.stats.timeattack.bestlap = unloadedmap->records.timeattack.lap;
|
||||
map.stats.spbattack.besttime = unloadedmap->records.spbattack.time;
|
||||
map.stats.spbattack.bestlap = unloadedmap->records.spbattack.lap;
|
||||
map.stats.time.total = unloadedmap->records.timeplayed;
|
||||
map.stats.time.netgame = unloadedmap->records.netgametimeplayed;
|
||||
map.stats.time.race = unloadedmap->records.modetimeplayed[GDGT_RACE];
|
||||
map.stats.time.battle = unloadedmap->records.modetimeplayed[GDGT_BATTLE];
|
||||
map.stats.time.prisons = unloadedmap->records.modetimeplayed[GDGT_PRISONS];
|
||||
map.stats.time.special = unloadedmap->records.modetimeplayed[GDGT_SPECIAL];
|
||||
map.stats.time.custom = unloadedmap->records.modetimeplayed[GDGT_CUSTOM];
|
||||
map.stats.time.timeattack = unloadedmap->records.timeattacktimeplayed;
|
||||
map.stats.time.spbattack = unloadedmap->records.spbattacktimeplayed;
|
||||
ng.maps[lumpname] = std::move(map);
|
||||
}
|
||||
for (int i = 0; i < gamedata->numspraycans; i++)
|
||||
|
|
@ -412,6 +450,16 @@ void srb2::load_ng_gamedata()
|
|||
gamedata->evercrashed = dirty;
|
||||
|
||||
gamedata->totalplaytime = js.playtime.total;
|
||||
gamedata->totalnetgametime = js.playtime.netgame;
|
||||
gamedata->timeattackingtotaltime = js.playtime.timeattack;
|
||||
gamedata->spbattackingtotaltime = js.playtime.spbattack;
|
||||
gamedata->modeplaytime[GDGT_RACE] = js.playtime.race;
|
||||
gamedata->modeplaytime[GDGT_BATTLE] = js.playtime.battle;
|
||||
gamedata->modeplaytime[GDGT_PRISONS] = js.playtime.prisons;
|
||||
gamedata->modeplaytime[GDGT_SPECIAL] = js.playtime.special;
|
||||
gamedata->modeplaytime[GDGT_CUSTOM] = js.playtime.custom;
|
||||
gamedata->totalmenutime = js.playtime.menus;
|
||||
gamedata->totaltimestaringatstatistics = js.playtime.statistics;
|
||||
gamedata->totalrings = js.rings.total;
|
||||
gamedata->totaltumbletime = js.playtime.tumble;
|
||||
gamedata->roundsplayed[GDGT_RACE] = js.rounds.race;
|
||||
|
|
@ -504,7 +552,23 @@ void srb2::load_ng_gamedata()
|
|||
{
|
||||
INT32 skin = R_SkinAvailableEx(skinpair.first.c_str(), false);
|
||||
skinrecord_t dummyrecord {};
|
||||
|
||||
dummyrecord.wins = skinpair.second.records.wins;
|
||||
dummyrecord.rounds = skinpair.second.records.rounds;
|
||||
|
||||
#ifdef DEVELOP
|
||||
// Only good for testing, not for active play... cheaters never prosper!
|
||||
if (dummyrecord.rounds < dummyrecord.wins)
|
||||
dummyrecord.rounds = dummyrecord.wins;
|
||||
#endif
|
||||
|
||||
dummyrecord.timeplayed = skinpair.second.records.time.total;
|
||||
dummyrecord.modetimeplayed[GDGT_RACE] = skinpair.second.records.time.race;
|
||||
dummyrecord.modetimeplayed[GDGT_BATTLE] = skinpair.second.records.time.battle;
|
||||
dummyrecord.modetimeplayed[GDGT_PRISONS] = skinpair.second.records.time.prisons;
|
||||
dummyrecord.modetimeplayed[GDGT_SPECIAL] = skinpair.second.records.time.special;
|
||||
dummyrecord.modetimeplayed[GDGT_CUSTOM] = skinpair.second.records.time.custom;
|
||||
dummyrecord.tumbletime = skinpair.second.records.time.tumble;
|
||||
|
||||
if (skin != -1)
|
||||
{
|
||||
|
|
@ -547,6 +611,15 @@ void srb2::load_ng_gamedata()
|
|||
dummyrecord.timeattack.lap = mappair.second.stats.timeattack.bestlap;
|
||||
dummyrecord.spbattack.time = mappair.second.stats.spbattack.besttime;
|
||||
dummyrecord.spbattack.lap = mappair.second.stats.spbattack.bestlap;
|
||||
dummyrecord.timeplayed = mappair.second.stats.time.total;
|
||||
dummyrecord.netgametimeplayed = mappair.second.stats.time.netgame;
|
||||
dummyrecord.modetimeplayed[GDGT_RACE] = mappair.second.stats.time.race;
|
||||
dummyrecord.modetimeplayed[GDGT_BATTLE] = mappair.second.stats.time.battle;
|
||||
dummyrecord.modetimeplayed[GDGT_PRISONS] = mappair.second.stats.time.prisons;
|
||||
dummyrecord.modetimeplayed[GDGT_SPECIAL] = mappair.second.stats.time.special;
|
||||
dummyrecord.modetimeplayed[GDGT_CUSTOM] = mappair.second.stats.time.custom;
|
||||
dummyrecord.timeattacktimeplayed = mappair.second.stats.time.timeattack;
|
||||
dummyrecord.spbattacktimeplayed = mappair.second.stats.time.spbattack;
|
||||
|
||||
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,9 +27,33 @@ namespace srb2
|
|||
struct GamedataPlaytimeJson final
|
||||
{
|
||||
uint32_t total;
|
||||
uint32_t netgame;
|
||||
uint32_t timeattack;
|
||||
uint32_t spbattack;
|
||||
uint32_t race;
|
||||
uint32_t battle;
|
||||
uint32_t prisons;
|
||||
uint32_t special;
|
||||
uint32_t custom;
|
||||
uint32_t menus;
|
||||
uint32_t statistics;
|
||||
uint32_t tumble;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataPlaytimeJson, total, tumble)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
GamedataPlaytimeJson,
|
||||
total,
|
||||
netgame,
|
||||
timeattack,
|
||||
spbattack,
|
||||
race,
|
||||
battle,
|
||||
prisons,
|
||||
special,
|
||||
custom,
|
||||
menus,
|
||||
statistics,
|
||||
tumble
|
||||
)
|
||||
};
|
||||
|
||||
struct GamedataRingsJson final
|
||||
|
|
@ -104,11 +128,40 @@ struct GamedataChallengeGridJson final
|
|||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataChallengeGridJson, width, grid)
|
||||
};
|
||||
|
||||
struct GamedataSkinRecordsPlaytimeJson final
|
||||
{
|
||||
uint32_t total;
|
||||
uint32_t race;
|
||||
uint32_t battle;
|
||||
uint32_t prisons;
|
||||
uint32_t special;
|
||||
uint32_t custom;
|
||||
uint32_t tumble;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
GamedataSkinRecordsPlaytimeJson,
|
||||
total,
|
||||
race,
|
||||
battle,
|
||||
prisons,
|
||||
special,
|
||||
custom,
|
||||
tumble
|
||||
)
|
||||
};
|
||||
|
||||
struct GamedataSkinRecordsJson final
|
||||
{
|
||||
uint32_t wins;
|
||||
uint32_t rounds;
|
||||
GamedataSkinRecordsPlaytimeJson time;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataSkinRecordsJson, wins)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
GamedataSkinRecordsJson,
|
||||
wins,
|
||||
rounds,
|
||||
time
|
||||
)
|
||||
};
|
||||
|
||||
struct GamedataSkinJson final
|
||||
|
|
@ -145,12 +198,44 @@ struct GamedataMapStatsSpbAttackJson final
|
|||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsSpbAttackJson, besttime, bestlap)
|
||||
};
|
||||
|
||||
struct GamedataMapStatsPlaytimeJson final
|
||||
{
|
||||
uint32_t total;
|
||||
uint32_t netgame;
|
||||
uint32_t race;
|
||||
uint32_t battle;
|
||||
uint32_t prisons;
|
||||
uint32_t special;
|
||||
uint32_t custom;
|
||||
uint32_t timeattack;
|
||||
uint32_t spbattack;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
GamedataMapStatsPlaytimeJson,
|
||||
total,
|
||||
netgame,
|
||||
race,
|
||||
battle,
|
||||
prisons,
|
||||
special,
|
||||
custom,
|
||||
timeattack,
|
||||
spbattack
|
||||
)
|
||||
};
|
||||
|
||||
struct GamedataMapStatsJson final
|
||||
{
|
||||
GamedataMapStatsTimeAttackJson timeattack;
|
||||
GamedataMapStatsSpbAttackJson spbattack;
|
||||
GamedataMapStatsPlaytimeJson time;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapStatsJson, timeattack, spbattack)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(
|
||||
GamedataMapStatsJson,
|
||||
timeattack,
|
||||
spbattack,
|
||||
time
|
||||
)
|
||||
};
|
||||
|
||||
struct GamedataMapJson final
|
||||
|
|
|
|||
|
|
@ -8207,11 +8207,19 @@ void K_KartPlayerHUDUpdate(player_t *player)
|
|||
else
|
||||
player->karthud[khud_finish] = 0;
|
||||
|
||||
// Tumble time stat update
|
||||
if (demo.playback == false && P_IsMachineLocalPlayer(player) == true)
|
||||
{
|
||||
if (player->tumbleBounces != 0 && gamedata->totaltumbletime != UINT32_MAX)
|
||||
{
|
||||
gamedata->totaltumbletime++;
|
||||
|
||||
if (player->skin >= 0 && player->skin < numskins)
|
||||
{
|
||||
skin_t *playerskin;
|
||||
playerskin = &skins[player->skin];
|
||||
playerskin->records.tumbletime++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1434,6 +1434,7 @@ typedef enum
|
|||
statisticspage_chars = 0,
|
||||
statisticspage_gp,
|
||||
statisticspage_maps,
|
||||
statisticspage_time,
|
||||
statisticspage_max
|
||||
} statisticspage_t;
|
||||
|
||||
|
|
|
|||
126
src/k_menudraw.c
126
src/k_menudraw.c
|
|
@ -8310,7 +8310,7 @@ static void M_DrawStatsChars(void)
|
|||
i = -1;
|
||||
|
||||
V_DrawThinString(20, y - 10, highlightflags, "CHARACTER");
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH/2 + 34, y - 10, highlightflags, "WINS");
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH/2 + 34, y - 10, highlightflags, "WINS/ROUNDS");
|
||||
|
||||
while ((skin = statisticsmenu.maplist[++i]) < numskins)
|
||||
{
|
||||
|
|
@ -8328,7 +8328,7 @@ static void M_DrawStatsChars(void)
|
|||
|
||||
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));
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH/2 + 30, y+3, 0, va("%d/%d", skins[skin].records.wins, skins[skin].records.rounds));
|
||||
|
||||
y += STATSSTEP;
|
||||
|
||||
|
|
@ -8474,10 +8474,103 @@ bottomarrow:
|
|||
|
||||
#undef STATSSTEP
|
||||
|
||||
static void M_GetStatsTime(char *beststr, UINT32 totaltime)
|
||||
{
|
||||
beststr[0] = 0;
|
||||
|
||||
boolean showallsubsequent = false;
|
||||
|
||||
UINT32 besttime = G_TicsToHours(totaltime);
|
||||
if (besttime)
|
||||
{
|
||||
showallsubsequent = true;
|
||||
if (besttime >= 24)
|
||||
{
|
||||
strcat(beststr, va("%u day%s, ", besttime/24, (besttime < 48 ? "" : "s")));
|
||||
besttime %= 24;
|
||||
}
|
||||
|
||||
strcat(beststr, va("%u hour%s, ", besttime, (besttime == 1 ? "" : "s")));
|
||||
}
|
||||
besttime = G_TicsToMinutes(totaltime, false);
|
||||
if (besttime || showallsubsequent)
|
||||
{
|
||||
showallsubsequent = true;
|
||||
strcat(beststr, va("%u minute%s, ", besttime, (besttime == 1 ? "" : "s")));
|
||||
}
|
||||
besttime = G_TicsToSeconds(totaltime);
|
||||
strcat(beststr, va("%i second%s", besttime, (besttime == 1 ? "" : "s")));
|
||||
}
|
||||
|
||||
static void M_DrawStatsTimeTracked(void)
|
||||
{
|
||||
INT32 y = 70;
|
||||
char beststr[256];
|
||||
|
||||
#define DISPLAYAMODE(str, besttime) \
|
||||
{ \
|
||||
V_DrawThinString(24, y, 0, str); \
|
||||
M_GetStatsTime(beststr, besttime); \
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-24, y, 0, beststr); \
|
||||
y += 10; \
|
||||
}
|
||||
|
||||
DISPLAYAMODE("Race Mode", gamedata->modeplaytime[GDGT_RACE]);
|
||||
|
||||
if (gamedata->roundsplayed[GDGT_PRISONS])
|
||||
{
|
||||
DISPLAYAMODE("Prison Break", gamedata->modeplaytime[GDGT_PRISONS]);
|
||||
}
|
||||
|
||||
DISPLAYAMODE("Battle Mode", gamedata->modeplaytime[GDGT_BATTLE]);
|
||||
|
||||
if (gamedata->roundsplayed[GDGT_SPECIAL])
|
||||
{
|
||||
DISPLAYAMODE("Special Mode", gamedata->modeplaytime[GDGT_SPECIAL]);
|
||||
}
|
||||
|
||||
if (gamedata->roundsplayed[GDGT_CUSTOM])
|
||||
{
|
||||
DISPLAYAMODE("All Custom Modes", gamedata->modeplaytime[GDGT_CUSTOM]);
|
||||
}
|
||||
|
||||
if (M_SecretUnlocked(SECRET_ONLINE, true))
|
||||
{
|
||||
y += 2;
|
||||
|
||||
DISPLAYAMODE("Playing Online", gamedata->totalnetgametime);
|
||||
}
|
||||
|
||||
if (M_SecretUnlocked(SECRET_TIMEATTACK, true)
|
||||
|| M_SecretUnlocked(SECRET_PRISONBREAK, true)
|
||||
|| M_SecretUnlocked(SECRET_SPECIALATTACK, true))
|
||||
{
|
||||
y += 2;
|
||||
|
||||
DISPLAYAMODE("Time Attack Modes", gamedata->timeattackingtotaltime);
|
||||
|
||||
if (M_SecretUnlocked(SECRET_SPBATTACK, true))
|
||||
{
|
||||
DISPLAYAMODE(" (SPB Attack)", gamedata->spbattackingtotaltime);
|
||||
}
|
||||
}
|
||||
|
||||
if (gamedata->totaltumbletime)
|
||||
{
|
||||
y += 2;
|
||||
|
||||
DISPLAYAMODE("Tumbling through the air", gamedata->totaltumbletime);
|
||||
}
|
||||
|
||||
y += 2;
|
||||
|
||||
DISPLAYAMODE("On Menus", gamedata->totalmenutime);
|
||||
DISPLAYAMODE(" (staring at this screen)", gamedata->totaltimestaringatstatistics);
|
||||
}
|
||||
|
||||
void M_DrawStatistics(void)
|
||||
{
|
||||
char beststr[256];
|
||||
tic_t besttime = 0;
|
||||
|
||||
{
|
||||
const char *pagename = NULL;
|
||||
|
|
@ -8487,7 +8580,6 @@ void M_DrawStatistics(void)
|
|||
|
||||
switch (statisticsmenu.page)
|
||||
{
|
||||
|
||||
case statisticspage_gp:
|
||||
{
|
||||
pagename = gamedata->everseenspecial
|
||||
|
|
@ -8511,6 +8603,13 @@ void M_DrawStatistics(void)
|
|||
break;
|
||||
}
|
||||
|
||||
case statisticspage_time:
|
||||
{
|
||||
pagename = "TIME TRACKED";
|
||||
M_DrawStatsTimeTracked();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -8528,26 +8627,9 @@ void M_DrawStatistics(void)
|
|||
0, "\x1D"); // right arrow
|
||||
}
|
||||
|
||||
beststr[0] = 0;
|
||||
V_DrawThinString(20, 30, highlightflags, "Total Play Time:");
|
||||
besttime = G_TicsToHours(gamedata->totalplaytime);
|
||||
if (besttime)
|
||||
{
|
||||
if (besttime >= 24)
|
||||
{
|
||||
strcat(beststr, va("%u day%s, ", besttime/24, (besttime < 48 ? "" : "s")));
|
||||
besttime %= 24;
|
||||
}
|
||||
|
||||
strcat(beststr, va("%u hour%s, ", besttime, (besttime == 1 ? "" : "s")));
|
||||
}
|
||||
besttime = G_TicsToMinutes(gamedata->totalplaytime, false);
|
||||
if (besttime)
|
||||
{
|
||||
strcat(beststr, va("%u minute%s, ", besttime, (besttime == 1 ? "" : "s")));
|
||||
}
|
||||
besttime = G_TicsToSeconds(gamedata->totalplaytime);
|
||||
strcat(beststr, va("%i second%s", besttime, (besttime == 1 ? "" : "s")));
|
||||
M_GetStatsTime(beststr, gamedata->totalplaytime);
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 30, 0, beststr);
|
||||
beststr[0] = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1429,6 +1429,12 @@ void M_Ticker(void)
|
|||
skullAnimCounter = 8;
|
||||
}
|
||||
|
||||
if (!Playing())
|
||||
{
|
||||
// Anything in M_Ticker that isn't actively playing is considered "in menus" for time tracking
|
||||
gamedata->totalmenutime++;
|
||||
}
|
||||
|
||||
if (!Playing() && !M_GameTrulyStarted())
|
||||
{
|
||||
M_GonerBGTick();
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ profile_t* PR_MakeProfile(
|
|||
memcpy(newprofile->controls, controlarray, sizeof(newprofile->controls));
|
||||
|
||||
newprofile->wins = 0;
|
||||
newprofile->rounds = 0;
|
||||
|
||||
return newprofile;
|
||||
}
|
||||
|
|
@ -293,6 +294,7 @@ void PR_SaveProfiles(void)
|
|||
jsonprof.followercolorname = std::string(skincolors[cprof->followercolor].name);
|
||||
}
|
||||
jsonprof.records.wins = cprof->wins;
|
||||
jsonprof.records.rounds = cprof->rounds;
|
||||
jsonprof.preferences.kickstartaccel = cprof->kickstartaccel;
|
||||
jsonprof.preferences.autoroulette = cprof->autoroulette;
|
||||
jsonprof.preferences.litesteer = cprof->litesteer;
|
||||
|
|
@ -458,6 +460,7 @@ void PR_LoadProfiles(void)
|
|||
}
|
||||
|
||||
newprof->wins = jsprof.records.wins;
|
||||
newprof->rounds = jsprof.records.rounds;
|
||||
newprof->kickstartaccel = jsprof.preferences.kickstartaccel;
|
||||
newprof->autoroulette = jsprof.preferences.autoroulette;
|
||||
newprof->litesteer = jsprof.preferences.litesteer;
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ namespace srb2
|
|||
struct ProfileRecordsJson
|
||||
{
|
||||
uint32_t wins;
|
||||
uint32_t rounds;
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfileRecordsJson, wins)
|
||||
NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(ProfileRecordsJson, wins, rounds)
|
||||
};
|
||||
|
||||
struct ProfilePreferencesJson
|
||||
|
|
@ -147,6 +148,7 @@ struct profile_t
|
|||
UINT16 followercolor; // Follower color
|
||||
|
||||
UINT32 wins; // I win I win I win
|
||||
UINT32 rounds; // I played I played I played
|
||||
|
||||
// Player-specific consvars.
|
||||
// @TODO: List all of those
|
||||
|
|
|
|||
21
src/m_cond.c
21
src/m_cond.c
|
|
@ -652,6 +652,13 @@ void M_ClearStats(void)
|
|||
{
|
||||
UINT8 i;
|
||||
gamedata->totalplaytime = 0;
|
||||
gamedata->totalnetgametime = 0;
|
||||
gamedata->timeattackingtotaltime = 0;
|
||||
gamedata->spbattackingtotaltime = 0;
|
||||
for (i = 0; i < GDGT_MAX; ++i)
|
||||
gamedata->modeplaytime[i] = 0;
|
||||
gamedata->totalmenutime = 0;
|
||||
gamedata->totaltimestaringatstatistics = 0;
|
||||
gamedata->totalrings = 0;
|
||||
gamedata->totaltumbletime = 0;
|
||||
for (i = 0; i < GDGT_MAX; ++i)
|
||||
|
|
@ -3823,3 +3830,17 @@ boolean M_UseAlternateTitleScreen(void)
|
|||
extern consvar_t cv_alttitle;
|
||||
return cv_alttitle.value && M_SecretUnlocked(SECRET_ALTTITLE, true);
|
||||
}
|
||||
|
||||
INT32 M_GameDataGameType(INT32 lgametype, boolean lbattleprisons)
|
||||
{
|
||||
INT32 playtimemode = GDGT_CUSTOM;
|
||||
if (lgametype == GT_RACE)
|
||||
playtimemode = GDGT_RACE;
|
||||
else if (lgametype == GT_BATTLE)
|
||||
playtimemode = lbattleprisons ? GDGT_PRISONS : GDGT_BATTLE;
|
||||
else if (lgametype == GT_SPECIAL || lgametype == GT_VERSUS)
|
||||
playtimemode = GDGT_SPECIAL;
|
||||
|
||||
return playtimemode;
|
||||
}
|
||||
|
||||
|
|
|
|||
16
src/m_cond.h
16
src/m_cond.h
|
|
@ -311,15 +311,6 @@ typedef enum {
|
|||
GDGONER_DONE,
|
||||
} gdgoner_t;
|
||||
|
||||
typedef enum {
|
||||
GDGT_RACE,
|
||||
GDGT_BATTLE,
|
||||
GDGT_PRISONS,
|
||||
GDGT_SPECIAL,
|
||||
GDGT_CUSTOM,
|
||||
GDGT_MAX
|
||||
} roundsplayed_t;
|
||||
|
||||
struct candata_t
|
||||
{
|
||||
UINT16 col;
|
||||
|
|
@ -369,6 +360,12 @@ struct gamedata_t
|
|||
|
||||
// PLAY TIME
|
||||
UINT32 totalplaytime;
|
||||
UINT32 totalnetgametime;
|
||||
UINT32 timeattackingtotaltime;
|
||||
UINT32 spbattackingtotaltime;
|
||||
UINT32 modeplaytime[GDGT_MAX];
|
||||
UINT32 totalmenutime;
|
||||
UINT32 totaltimestaringatstatistics;
|
||||
UINT32 roundsplayed[GDGT_MAX];
|
||||
UINT32 totalrings;
|
||||
UINT32 totaltumbletime;
|
||||
|
|
@ -495,6 +492,7 @@ UINT16 M_EmblemMapNum(emblem_t *emblem);
|
|||
#define M_Achieved(a) ((a) >= MAXCONDITIONSETS || gamedata->achieved[a])
|
||||
|
||||
boolean M_UseAlternateTitleScreen(void);
|
||||
INT32 M_GameDataGameType(INT32 gametype, boolean battleprisons);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
extras-addons.c
|
||||
extras-challenges.c
|
||||
extras-egg-tv.cpp
|
||||
extras-statistics.c
|
||||
extras-statistics.cpp
|
||||
extras-wrong.c
|
||||
main-1.c
|
||||
main-goner.cpp
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@
|
|||
extern consvar_t cv_debugchallenges;
|
||||
#endif
|
||||
|
||||
static void M_StatisticsTicker(void)
|
||||
{
|
||||
// the funny
|
||||
gamedata->totaltimestaringatstatistics++;
|
||||
}
|
||||
|
||||
menuitem_t MISC_ChallengesStatsDummyMenu[] =
|
||||
{
|
||||
{IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0},
|
||||
|
|
@ -60,7 +66,7 @@ menu_t MISC_StatisticsDef = {
|
|||
98, 0,
|
||||
M_DrawStatistics,
|
||||
M_DrawExtrasBack,
|
||||
NULL,
|
||||
M_StatisticsTicker,
|
||||
NULL,
|
||||
NULL,
|
||||
M_StatisticsInputs,
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ static void M_StatisticsMaps(void)
|
|||
UINT16 i;
|
||||
boolean headerexists;
|
||||
|
||||
statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (nummapheaders+1 + numkartcupheaders), PU_STATIC, NULL);
|
||||
statisticsmenu.maplist = static_cast<UINT16*>(Z_Malloc(sizeof(UINT16) * (nummapheaders+1 + numkartcupheaders), PU_STATIC, NULL));
|
||||
statisticsmenu.nummaps = 0;
|
||||
|
||||
// Cups
|
||||
|
|
@ -119,7 +119,7 @@ static void M_StatisticsChars(void)
|
|||
{
|
||||
UINT16 i;
|
||||
|
||||
statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (1 + numskins), PU_STATIC, NULL);
|
||||
statisticsmenu.maplist = static_cast<UINT16*>(Z_Malloc(sizeof(UINT16) * (1 + numskins), PU_STATIC, NULL));
|
||||
statisticsmenu.nummaps = 0;
|
||||
|
||||
UINT32 beststat = 0;
|
||||
|
|
@ -166,6 +166,19 @@ static void M_StatisticsChars(void)
|
|||
|
||||
statisticsmenu.maplist[statisticsmenu.nummaps] = MAXSKINS;
|
||||
|
||||
std::sort(
|
||||
statisticsmenu.maplist,
|
||||
statisticsmenu.maplist + statisticsmenu.nummaps,
|
||||
[](UINT16 a, UINT16 b) {
|
||||
if (skins[a].records.rounds > skins[b].records.rounds)
|
||||
return true;
|
||||
if (skins[a].records.rounds != skins[b].records.rounds)
|
||||
return false;
|
||||
// Stable for skin ID
|
||||
return (a < b);
|
||||
}
|
||||
);
|
||||
|
||||
statisticsmenu.location = 0;
|
||||
statisticsmenu.maxscroll = statisticsmenu.nummaps - 6;
|
||||
|
||||
|
|
@ -208,7 +221,7 @@ static void M_StatisticsChars(void)
|
|||
|
||||
static void M_StatisticsGP(void)
|
||||
{
|
||||
statisticsmenu.maplist = Z_Malloc(sizeof(UINT16) * (1 + numkartcupheaders), PU_STATIC, NULL);
|
||||
statisticsmenu.maplist = static_cast<UINT16*>(Z_Malloc(sizeof(UINT16) * (1 + numkartcupheaders), PU_STATIC, NULL));
|
||||
statisticsmenu.nummaps = 0;
|
||||
|
||||
cupheader_t *cup;
|
||||
|
|
@ -255,7 +268,10 @@ static void M_StatisticsPageInit(void)
|
|||
}
|
||||
|
||||
default:
|
||||
{
|
||||
statisticsmenu.maplist = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -302,15 +318,17 @@ boolean M_StatisticsInputs(INT32 ch)
|
|||
{
|
||||
M_StatisticsPageClear();
|
||||
|
||||
statisticsmenu.page +=
|
||||
statisticspage_max
|
||||
int newpage = static_cast<int>(statisticsmenu.page)
|
||||
+ static_cast<int>(statisticspage_max)
|
||||
+ (
|
||||
(menucmd[pid].dpad_lr > 0)
|
||||
? 1
|
||||
: -1
|
||||
);
|
||||
|
||||
statisticsmenu.page %= statisticspage_max;
|
||||
newpage %= static_cast<int>(statisticspage_max);
|
||||
|
||||
statisticsmenu.page = static_cast<statisticspage_t>(newpage);
|
||||
|
||||
M_StatisticsPageInit();
|
||||
|
||||
106
src/p_tick.c
106
src/p_tick.c
|
|
@ -941,9 +941,115 @@ void P_Ticker(boolean run)
|
|||
|
||||
if (gamedata && gamestate == GS_LEVEL && !demo.playback)
|
||||
{
|
||||
mapheader_t *mapheader;
|
||||
|
||||
mapheader = mapheaderinfo[gamemap - 1];
|
||||
|
||||
// Keep track of how long they've been playing!
|
||||
gamedata->totalplaytime++;
|
||||
|
||||
// Map playtime
|
||||
if (mapheader)
|
||||
{
|
||||
mapheader->records.timeplayed++;
|
||||
}
|
||||
|
||||
// Netgame total time
|
||||
if (netgame)
|
||||
{
|
||||
gamedata->totalnetgametime++;
|
||||
|
||||
if (mapheader)
|
||||
{
|
||||
mapheader->records.netgametimeplayed++;
|
||||
}
|
||||
}
|
||||
|
||||
// Per-skin total playtime for all machine-local players
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
skin_t *playerskin;
|
||||
|
||||
if (!P_IsMachineLocalPlayer(&players[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (players[i].skin >= numskins)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
playerskin = &skins[players[i].skin];
|
||||
|
||||
playerskin->records.timeplayed++;
|
||||
}
|
||||
|
||||
if (gametype != GT_TUTORIAL)
|
||||
{
|
||||
INT32 mode = M_GameDataGameType(gametype, battleprisons);
|
||||
|
||||
// Gamedata mode playtime
|
||||
if (mode >= 0 && mode < GDGT_MAX)
|
||||
{
|
||||
gamedata->modeplaytime[mode]++;
|
||||
if (mapheader)
|
||||
{
|
||||
mapheader->records.modetimeplayed[mode]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Attacking mode playtime
|
||||
if (modeattacking != ATTACKING_NONE)
|
||||
{
|
||||
if (encoremode) // ((modeattacking & ATTACKING_SPB) != 0)
|
||||
{
|
||||
gamedata->spbattackingtotaltime++;
|
||||
if (mapheader)
|
||||
{
|
||||
mapheader->records.spbattacktimeplayed++;
|
||||
}
|
||||
}
|
||||
//else
|
||||
{
|
||||
gamedata->timeattackingtotaltime++;
|
||||
if (mapheader)
|
||||
{
|
||||
mapheader->records.timeattacktimeplayed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Per-skin mode playtime
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
skin_t *playerskin;
|
||||
|
||||
if (!P_IsMachineLocalPlayer(&players[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (players[i].skin >= numskins)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
playerskin = &skins[players[i].skin];
|
||||
playerskin->records.modetimeplayed[mode]++;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO would this be laggy with more conditions in play...
|
||||
if (
|
||||
(leveltime > introtime
|
||||
|
|
|
|||
21
src/p_user.c
21
src/p_user.c
|
|
@ -1315,18 +1315,31 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
G_UpdateRecords();
|
||||
}
|
||||
|
||||
if (!losing)
|
||||
// Profile and skin record updates
|
||||
if (P_IsMachineLocalPlayer(player))
|
||||
{
|
||||
profile_t *pr = PR_GetPlayerProfile(player);
|
||||
|
||||
// Profile records
|
||||
if (pr != NULL)
|
||||
{
|
||||
pr->wins++;
|
||||
if (!losing)
|
||||
{
|
||||
pr->wins++;
|
||||
}
|
||||
pr->rounds++;
|
||||
PR_SaveProfiles();
|
||||
}
|
||||
|
||||
if (P_IsMachineLocalPlayer(player) && player->skin < numskins)
|
||||
// Skin records (saved to gamedata)
|
||||
if (player->skin < numskins)
|
||||
{
|
||||
skins[player->skin].records.wins++;
|
||||
skin_t *playerskin = &skins[player->skin];
|
||||
if (!losing)
|
||||
{
|
||||
playerskin->records.wins++;
|
||||
}
|
||||
playerskin->records.rounds++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue