Add kartstats

4942db2806
This commit is contained in:
NepDisk 2025-02-25 14:00:10 -05:00
parent 475524e7ad
commit 8b142ceb62
12 changed files with 229 additions and 28 deletions

View file

@ -129,3 +129,4 @@ k_brightmap.c
k_director.c
k_follower.c
k_mapuser.c
k_stats.c

View file

@ -557,9 +557,6 @@ struct tolinfo_t
extern tolinfo_t TYPEOFLEVEL[NUMTOLNAMES];
extern UINT32 lastcustomtol;
extern tic_t totalplaytime;
extern UINT32 matchesplayed;
extern UINT8 stagefailed;
// Emeralds stored as bits to throw savegame hackers off.

View file

@ -53,6 +53,7 @@
// SRB2kart
#include "k_kart.h"
#include "k_stats.h" // SRB2kart
#include "k_battle.h"
#include "k_pwrlv.h"
#include "k_color.h"
@ -196,8 +197,6 @@ UINT32 tokenlist; // List of tokens collected
boolean gottoken; // Did you get a token? Used for end of act
INT32 tokenbits; // Used for setting token bits
tic_t totalplaytime;
UINT32 matchesplayed; // SRB2Kart
boolean gamedataloaded = false;
// Temporary holding place for nights data for the current map
@ -2198,7 +2197,7 @@ static inline void G_PlayerFinishLevel(INT32 player)
{
if (legitimateexit && !demo.playback && !mapreset) // (yes you're allowed to unlock stuff this way when the game is modified)
{
matchesplayed++;
kartstats.matchesplayed++;
if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_ncitem);
G_SaveGameData();
@ -4044,6 +4043,7 @@ static void G_DoCompleted(void)
if (!demo.playback)
{
nextmap = G_GetNextMap(true);
K_StatRound();
// Remember last map for when you come out of the special stage.
if (!spec)
@ -4301,9 +4301,6 @@ void G_LoadGameData(void)
G_ClearRecords(); // main and nights records
M_ClearSecrets(); // emblems, unlocks, maps visited, etc
totalplaytime = 0; // total play time (separate from all)
matchesplayed = 0; // SRB2Kart: matches played & finished
for (i = 0; i < PWRLV_NUMTYPES; i++) // SRB2Kart: online rank system
vspowerlevel[i] = PWRLVRECORD_START;
@ -4334,9 +4331,8 @@ void G_LoadGameData(void)
P_SaveBufferFree(&save);
I_Error("Game data is not for SRB2Kart v2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
}
totalplaytime = READUINT32(save.p);
matchesplayed = READUINT32(save.p);
K_ReadStats(&save, true);
for (i = 0; i < PWRLV_NUMTYPES; i++)
{
@ -4486,8 +4482,7 @@ void G_SaveGameData(void)
// Version test
WRITEUINT32(save.p, GD_VERSIONCHECK); // 4
WRITEUINT32(save.p, totalplaytime); // 4
WRITEUINT32(save.p, matchesplayed); // 4
K_WriteStats(&save, true);
for (i = 0; i < PWRLV_NUMTYPES; i++)
WRITEUINT16(save.p, vspowerlevel[i]);

View file

@ -2,6 +2,7 @@
/// \brief SRB2Kart item collision hooks
#include "k_collide.h"
#include "k_stats.h"
#include "doomstat.h"
#include "doomtype.h"
#include "p_mobj.h"
@ -800,6 +801,8 @@ boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2)
if (t2->player->flashing > 0)
return true;
K_StatPlayerSink(t1->player, P_MobjWasRemoved(t2->target) ? NULL : t2->target->player);
S_StartSound(NULL, sfx_cgot); //let all players hear it.
HU_SetCEchoFlags(0);

View file

@ -38,6 +38,8 @@
#include "m_cheat.h" // objectplacing
#include "p_spec.h"
#include "k_stats.h"
#include "k_waypoint.h"
#include "k_bot.h"
#include "k_hud.h"
@ -3620,6 +3622,7 @@ void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 typ
S_StartSound(player->mo, sfx_slip);
}
K_StatPlayerHit(player, source ? source->player : NULL);
player->spinouttimer = (3*TICRATE/2)+2;
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
}

146
src/k_stats.c Normal file
View file

@ -0,0 +1,146 @@
#include "k_stats.h"
#include "doomstat.h"
#include "g_game.h"
#include "byteptr.h"
kartstats_t kartstats = {0};
void K_StatTicker(void)
{
if (demo.playback)
return;
kartstats.totalplaytime++;
if (netgame)
kartstats.onlineplaytime++;
else if (modeattacking)
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->kartstuff[k_position] == spbplace)
kartstats.spbtargettime++;
if (max(p->kartstuff[k_spinouttimer], p->kartstuff[k_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;
int numplayers = 0;
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i] && !players[i].spectator)
++numplayers;
}
if (numplayers > 1)
{
if (players[consoleplayer].kartstuff[k_position] == 1)
kartstats.totalwins++;
else if (players[consoleplayer].kartstuff[k_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;
memset(&kartstats, 0, sizeof(kartstats_t));
kartstats.vanilla = vanilla;
}
void K_ReadStats(savebuffer_t *save, boolean vanilla)
{
memset(&kartstats, 0, sizeof(kartstats_t));
kartstats.vanilla = vanilla;
kartstats.totalplaytime = READUINT32(save->p);
kartstats.matchesplayed = READUINT32(save->p);
// Vanilla only has those 2
if (vanilla)
return;
// 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);
}
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;
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);
}

56
src/k_stats.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef __K_STATS__
#define __K_STATS__
#include "doomtype.h"
#include "d_player.h"
#include "p_saveg.h"
typedef struct kartstats_s {
// Remember if stats we loaded are vanilla ones or not
boolean vanilla;
// Vanilla
tic_t totalplaytime;
UINT32 matchesplayed;
tic_t raplaytime;
tic_t onlineplaytime;
tic_t raceplaytime;
tic_t battleplaytime;
tic_t spbtargettime;
tic_t spinouttime;
UINT32 totalwins; // 1st place
UINT32 totalpodium; // 2nd and 3rd place, *but not 1st*
UINT32 hits;
UINT32 selfhits;
UINT32 sinks; // Times hitting *others* by kitchen sink
UINT32 sinked; // Times *being hit* by kitchen sink
UINT32 respawns;
} kartstats_t;
extern kartstats_t kartstats;
// Note: All stat-tracking functions check for demo.playback and early return if its true
// Update global stats such as total play time, etc
void K_StatTicker(void);
// Update hit-related stats (PlayerSpin, PlayerSquish, PlayerExplode)
void K_StatPlayerHit(player_t *victim, player_t *source);
// Separate from stuff above
void K_StatPlayerSink(player_t *victim, player_t *source);
// Update round-related stats (such as matchesplayed, totalwins, etc)
void K_StatRound(void);
void K_EraseStats(void);
// If vanilla is true, only read vanilla-supported fields. Everything else is initialized to 0
void K_ReadStats(savebuffer_t *save, boolean vanilla);
// Same as above, except it just doesn't write non-vanilla fields if vanilla is true
void K_WriteStats(savebuffer_t *save, boolean vanilla);
#endif

View file

@ -21,6 +21,7 @@
#include "r_skins.h" // numskins
#include "r_draw.h" // R_GetColorByName
#include "k_pwrlv.h"
#include "k_stats.h"
// Map triggers for linedef executors
// 32 triggers, one bit each
@ -174,9 +175,9 @@ UINT8 M_CheckCondition(condition_t *cn)
switch (cn->type)
{
case UC_PLAYTIME: // Requires total playing time >= x
return (totalplaytime >= (unsigned)cn->requirement);
return (kartstats.totalplaytime >= (unsigned)cn->requirement);
case UC_MATCHESPLAYED: // Requires any level completed >= x times
return (matchesplayed >= (unsigned)cn->requirement);
return (kartstats.matchesplayed >= (unsigned)cn->requirement);
case UC_POWERLEVEL: // Requires power level >= x on a certain gametype
return (vspowerlevel[cn->extrainfo1] >= (unsigned)cn->requirement);
case UC_GAMECLEAR: // Requires game beaten >= x times

View file

@ -64,6 +64,7 @@
#include "k_hud.h" // SRB2kart
#include "k_kart.h" // KartItemCVars
#include "k_pwrlv.h"
#include "k_stats.h" // SRB2kart
#include "d_player.h" // KITEM_ constants
#include "k_color.h"
#include "k_grandprix.h"
@ -7682,12 +7683,11 @@ static void M_DrawLevelStats(void)
V_DrawString(20, 24, highlightflags, "Total Play Time:");
V_DrawCenteredString(BASEVIDWIDTH/2, 32, 0, va("%i hours, %i minutes, %i seconds",
G_TicsToHours(totalplaytime),
G_TicsToMinutes(totalplaytime, false),
G_TicsToSeconds(totalplaytime)));
G_TicsToHours(kartstats.totalplaytime),
G_TicsToMinutes(kartstats.totalplaytime, false),
G_TicsToSeconds(kartstats.totalplaytime)));
V_DrawString(20, 42, highlightflags, "Total Matches:");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 42, 0, va("%i played", matchesplayed));
V_DrawRightAlignedString(BASEVIDWIDTH-16, 42, 0, va("%i played", kartstats.matchesplayed));
V_DrawString(20, 52, highlightflags, "Online Power Level:");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 52, 0, va("Race: %i", vspowerlevel[PWRLV_RACE]));
@ -10249,8 +10249,7 @@ static void M_EraseDataResponse(INT32 ch)
if (erasecontext == 2)
{
// SRB2Kart: This actually needs to be done FIRST, so that you don't immediately regain playtime/matches secrets
totalplaytime = 0;
matchesplayed = 0;
K_EraseStats();
for (i = 0; i < PWRLV_NUMTYPES; i++)
vspowerlevel[i] = PWRLVRECORD_START;
F_StartIntro();

View file

@ -14,7 +14,7 @@
#include "doomdef.h"
#include "doomtype.h"
#include "doomstat.h" // totalplaytime
#include "k_stats.h" // kartstats.totalplaytime
#include "m_random.h"
#include "m_fixed.h"
@ -252,5 +252,5 @@ void P_SetRandSeedD(const char *rfile, INT32 rline, UINT32 seed)
*/
UINT32 M_RandomizedSeed(void)
{
return ((totalplaytime & 0xFFFF) << 16)|M_RandomFixed();
return ((kartstats.totalplaytime & 0xFFFF) << 16)|M_RandomFixed();
}

View file

@ -25,7 +25,7 @@
#include "r_sky.h"
#include "s_sound.h"
#include "w_wad.h"
#include "k_stats.h"
#include "k_kart.h" // SRB2kart 011617
#include "k_collide.h"
#include "hu_stuff.h" // SRB2kart

View file

@ -22,6 +22,7 @@
#include "m_random.h"
#include "lua_script.h"
#include "lua_hook.h"
#include "k_stats.h"
#include "m_perfstats.h"
#include "i_system.h" // I_GetPreciseTime
#include "i_video.h"
@ -746,8 +747,7 @@ void P_Ticker(boolean run)
}
// Keep track of how long they've been playing!
if (!demo.playback) // Don't increment if a demo is playing.
totalplaytime++;
K_StatTicker();
// formality so kitemcap gets updated properly each frame.
P_RunKartItems();