233 lines
6.3 KiB
C
233 lines
6.3 KiB
C
#include "k_stats.h"
|
|
#include "doomstat.h"
|
|
#include "g_game.h"
|
|
#include "byteptr.h"
|
|
#include "z_zone.h"
|
|
|
|
kartstats_t kartstats = {0};
|
|
|
|
void K_StatTicker(void)
|
|
{
|
|
if (demo.playback)
|
|
return;
|
|
|
|
maprecord_t *record = G_AllocateMapRecord(G_BuildMapName(gamemap));
|
|
record->playtime++;
|
|
kartstats.totalplaytime++;
|
|
|
|
if (netgame)
|
|
{
|
|
kartstats.onlineplaytime++;
|
|
}
|
|
else if (modeattacking)
|
|
{
|
|
maprecordpreset_t *preset = G_AllocateMapRecordPreset(record, currentrecordpreset, currentrecordpresetversion);
|
|
preset->playtime++;
|
|
kartstats.raplaytime++;
|
|
}
|
|
|
|
if (gametype == GT_RACE)
|
|
kartstats.raceplaytime++;
|
|
else if (gametype == GT_BATTLE)
|
|
kartstats.battleplaytime++;
|
|
|
|
// Should this also track splitscreen players?
|
|
if (!players[consoleplayer].spectator)
|
|
{
|
|
player_t *p = &players[consoleplayer];
|
|
|
|
if (p->position == spbplace)
|
|
kartstats.spbtargettime++;
|
|
|
|
if (p->flipovertimer > 0)
|
|
kartstats.spinouttime++;
|
|
else if (max(p->spinouttimer, p->wipeoutslow) > 0)
|
|
kartstats.spinouttime++;
|
|
}
|
|
}
|
|
|
|
void K_StatPlayerHit(player_t *victim, player_t *source)
|
|
{
|
|
if (demo.playback)
|
|
return;
|
|
|
|
if (victim == &players[consoleplayer])
|
|
{
|
|
if (victim == source)
|
|
kartstats.selfhits++;
|
|
}
|
|
else if (source == &players[consoleplayer])
|
|
kartstats.hits++;
|
|
}
|
|
|
|
void K_StatPlayerSink(player_t *victim, player_t *source)
|
|
{
|
|
if (demo.playback)
|
|
return;
|
|
|
|
if (victim == &players[consoleplayer])
|
|
kartstats.sinked++;
|
|
else if (source == &players[consoleplayer])
|
|
kartstats.sinks++;
|
|
}
|
|
|
|
void K_StatRound(void)
|
|
{
|
|
if (demo.playback)
|
|
return;
|
|
|
|
maprecord_t *record = G_AllocateMapRecord(G_BuildMapName(gamemap));
|
|
record->roundsplayed++;
|
|
kartstats.matchesplayed++;
|
|
|
|
int numplayers = 0;
|
|
|
|
for (int i = 0; i < MAXPLAYERS; ++i)
|
|
{
|
|
if (playeringame[i] && !players[i].spectator)
|
|
++numplayers;
|
|
}
|
|
|
|
if (numplayers > 1 && !players[consoleplayer].spectator)
|
|
{
|
|
if (players[consoleplayer].position == 1)
|
|
{
|
|
record->roundswon++;
|
|
kartstats.totalwins++;
|
|
}
|
|
else if (players[consoleplayer].position <= 3) // Should this check if there are more than 3 players in game?
|
|
{
|
|
kartstats.totalpodium++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void K_EraseStats(void)
|
|
{
|
|
// The only field we want to remember
|
|
boolean vanilla = kartstats.vanilla;
|
|
|
|
if (kartstats.copy)
|
|
Z_Free(kartstats.copy);
|
|
|
|
memset(&kartstats, 0, sizeof(kartstats_t));
|
|
|
|
kartstats.vanilla = vanilla;
|
|
}
|
|
|
|
static void K_ReadStatsCustom(savebuffer_t *save)
|
|
{
|
|
kartstats.size = READUINT32(save->p);
|
|
kartstats.version = READUINT32(save->p);
|
|
|
|
// So many similar-looking read's... scary...
|
|
kartstats.raplaytime = READUINT32(save->p);
|
|
kartstats.onlineplaytime = READUINT32(save->p);
|
|
kartstats.raceplaytime = READUINT32(save->p);
|
|
kartstats.battleplaytime = READUINT32(save->p);
|
|
kartstats.spbtargettime = READUINT32(save->p);
|
|
kartstats.spinouttime = READUINT32(save->p);
|
|
kartstats.totalwins = READUINT32(save->p);
|
|
kartstats.totalpodium = READUINT32(save->p);
|
|
kartstats.hits = READUINT32(save->p);
|
|
kartstats.selfhits = READUINT32(save->p);
|
|
kartstats.sinks = READUINT32(save->p);
|
|
kartstats.sinked = READUINT32(save->p);
|
|
kartstats.respawns = READUINT32(save->p);
|
|
|
|
// If kartstats gets updated, uncomment this and read next fields after this early return. Do same on next updates,
|
|
// this way even data is read on different versions, it doesn't get corrupted (as long as fields aren't removed, which shouldn't happen)
|
|
//if (kartstats.version < 2)
|
|
// return;
|
|
//
|
|
//kartstats.somenewfield = READUINT32(save->p);
|
|
}
|
|
|
|
void K_ReadStats(savebuffer_t *save, boolean vanilla)
|
|
{
|
|
// Basically, free old kartstats.copy if needed and memset kartstats with zeros
|
|
K_EraseStats();
|
|
|
|
kartstats.vanilla = vanilla;
|
|
|
|
kartstats.totalplaytime = READUINT32(save->p);
|
|
kartstats.matchesplayed = READUINT32(save->p);
|
|
|
|
// Vanilla only has those 2
|
|
if (vanilla)
|
|
return;
|
|
|
|
// Save where block of custom stats starts
|
|
UINT8 *customblockstart = save->p;
|
|
|
|
K_ReadStatsCustom(save);
|
|
|
|
// Make a copy of entire custom stats block, so unread values will still be written back
|
|
kartstats.copy = Z_Malloc(kartstats.size, PU_STATIC, NULL);
|
|
memcpy(kartstats.copy, customblockstart, kartstats.size);
|
|
|
|
// If there were extra fields we couldn't read, skip them
|
|
save->p = customblockstart + kartstats.size;
|
|
}
|
|
|
|
static void K_WriteStatsCustom(savebuffer_t *save)
|
|
{
|
|
// Update, if needed
|
|
kartstats.version = max(kartstats.version, KARTSTATSVERSION);
|
|
|
|
WRITEUINT32(save->p, kartstats.size); // Note: if we will end up writing more that stored in there, this field in save file would be updated
|
|
WRITEUINT32(save->p, kartstats.version);
|
|
|
|
// Version 1
|
|
WRITEUINT32(save->p, kartstats.raplaytime);
|
|
WRITEUINT32(save->p, kartstats.onlineplaytime);
|
|
WRITEUINT32(save->p, kartstats.raceplaytime);
|
|
WRITEUINT32(save->p, kartstats.battleplaytime);
|
|
WRITEUINT32(save->p, kartstats.spbtargettime);
|
|
WRITEUINT32(save->p, kartstats.spinouttime);
|
|
WRITEUINT32(save->p, kartstats.totalwins);
|
|
WRITEUINT32(save->p, kartstats.totalpodium);
|
|
WRITEUINT32(save->p, kartstats.hits);
|
|
WRITEUINT32(save->p, kartstats.selfhits);
|
|
WRITEUINT32(save->p, kartstats.sinks);
|
|
WRITEUINT32(save->p, kartstats.sinked);
|
|
WRITEUINT32(save->p, kartstats.respawns);
|
|
|
|
// No need for early returns, but please mark each new block of write's with version it corresponds to :3
|
|
|
|
// Version 2
|
|
//WRITEUINT32(save->p, kartstats.somenewfield);
|
|
}
|
|
|
|
void K_WriteStats(savebuffer_t *save, boolean vanilla)
|
|
{
|
|
WRITEUINT32(save->p, kartstats.totalplaytime);
|
|
WRITEUINT32(save->p, kartstats.matchesplayed);
|
|
|
|
// Vanilla only has those 2
|
|
if (vanilla)
|
|
return;
|
|
|
|
// Now need to be careful... We save start of custom stats block
|
|
UINT8 *customblockstart = save->p;
|
|
|
|
// Write everything we know how to write
|
|
K_WriteStatsCustom(save);
|
|
|
|
// Calculate size of data that we wrote
|
|
UINT32 size = (UINT32)(save->p - customblockstart);
|
|
|
|
// Now, if we wrote less data than save originally had, that means our copy that we kept in K_ReadStats
|
|
// has stats from newer version that we need to append
|
|
if (size < kartstats.size)
|
|
{
|
|
I_Assert(kartstats.copy != NULL); // If kartstats.copy is null, kartstats.size **always** should be 0, this can only happen if we create new save
|
|
WRITEMEM(save->p, kartstats.copy + size, kartstats.size - size);
|
|
}
|
|
else if (size > kartstats.size) // No need to do anything if we wrote exactly same amount...
|
|
{
|
|
// ...but, if we wrote more, we need to update size field in header. **It's always located at start of block**
|
|
// So we can just:
|
|
WRITEUINT32(customblockstart, size);
|
|
}
|
|
}
|