mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Character win records
Track wins per character. - If you have an existing gamedata of minor version 2 or earlier, attempt to import your last-used profile's wins onto the character you last used on that profile, so you're not starting from nothing. It's not quite accurate, but it's something. - Much like map headers and cups, these are also tracked in an unloaded_skins_t linked list. That work was done in this commit because gamedata is actually loaded before even base-game characters, which is annoying but at least confirmed it was working quicker. - TEMPORARY: Your per-character wins are displayed in your latest-log.txt, in lieu of an update to the in-game statistics menu
This commit is contained in:
parent
aa35e249d5
commit
1527471678
8 changed files with 221 additions and 4 deletions
15
src/d_main.c
15
src/d_main.c
|
|
@ -1851,6 +1851,21 @@ void D_SRB2Main(void)
|
|||
{
|
||||
PR_ApplyProfile(cv_ttlprofilen.value, 0);
|
||||
|
||||
if (gamedata->importprofilewins == true)
|
||||
{
|
||||
profile_t *pr = PR_GetProfile(cv_ttlprofilen.value);
|
||||
if (pr != NULL)
|
||||
{
|
||||
INT32 importskin = R_SkinAvailable(pr->skinname);
|
||||
if (importskin != -1)
|
||||
{
|
||||
CONS_Printf(" Wins for profile \"%s\" imported onto character \"%s\"\n", pr->profilename, skins[importskin].name);
|
||||
skins[importskin].records.wins = pr->wins;
|
||||
}
|
||||
}
|
||||
gamedata->importprofilewins = false;
|
||||
}
|
||||
|
||||
for (i = 1; i < cv_splitplayers.value; i++)
|
||||
{
|
||||
PR_ApplyProfile(cv_lastprofile[i].value, i);
|
||||
|
|
|
|||
132
src/g_game.c
132
src/g_game.c
|
|
@ -453,6 +453,11 @@ void G_ClearRecords(void)
|
|||
{
|
||||
UINT16 i;
|
||||
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
memset(&skins[i].records, 0, sizeof(skins[i].records));
|
||||
}
|
||||
|
||||
for (i = 0; i < nummapheaders; i++)
|
||||
{
|
||||
memset(&mapheaderinfo[i]->records, 0, sizeof(recorddata_t));
|
||||
|
|
@ -464,6 +469,14 @@ void G_ClearRecords(void)
|
|||
memset(&cup->windata, 0, sizeof(cup->windata));
|
||||
}
|
||||
|
||||
unloaded_skin_t *unloadedskin, *nextunloadedskin = NULL;
|
||||
for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = nextunloadedskin)
|
||||
{
|
||||
nextunloadedskin = unloadedskin->next;
|
||||
Z_Free(unloadedskin);
|
||||
}
|
||||
unloadedskins = NULL;
|
||||
|
||||
unloaded_mapheader_t *unloadedmap, *nextunloadedmap = NULL;
|
||||
for (unloadedmap = unloadedmapheaders; unloadedmap; unloadedmap = nextunloadedmap)
|
||||
{
|
||||
|
|
@ -4775,6 +4788,7 @@ void G_LoadGameData(void)
|
|||
savebuffer_t save = {0};
|
||||
|
||||
//For records
|
||||
UINT32 numgamedataskins;
|
||||
UINT32 numgamedatamapheaders;
|
||||
UINT32 numgamedatacups;
|
||||
|
||||
|
|
@ -4940,6 +4954,58 @@ void G_LoadGameData(void)
|
|||
gamedata->timesBeaten = READUINT32(save.p);
|
||||
|
||||
// Main records
|
||||
|
||||
if (versionMinor < 3)
|
||||
gamedata->importprofilewins = true;
|
||||
else
|
||||
{
|
||||
numgamedataskins = READUINT32(save.p);
|
||||
|
||||
for (i = 0; i < numgamedataskins; i++)
|
||||
{
|
||||
char skinname[SKINNAMESIZE+1];
|
||||
INT32 skin;
|
||||
|
||||
READSTRINGN(save.p, skinname, SKINNAMESIZE);
|
||||
skin = R_SkinAvailable(skinname);
|
||||
|
||||
skinrecord_t dummyrecord;
|
||||
|
||||
dummyrecord.wins = READUINT32(save.p);
|
||||
|
||||
CONS_Printf(" (TEMPORARY DISPLAY) skinname is \"%s\", has %u wins\n", skinname, dummyrecord.wins);
|
||||
|
||||
if (skin != -1)
|
||||
{
|
||||
// We found a skin, so assign the win.
|
||||
|
||||
M_Memcpy(&skins[skin].records, &dummyrecord, sizeof(skinrecord_t));
|
||||
}
|
||||
else if (dummyrecord.wins)
|
||||
{
|
||||
// Invalid, but we don't want to lose all the juicy statistics.
|
||||
// Instead, update a FILO linked list of "unloaded skins".
|
||||
|
||||
unloaded_skin_t *unloadedskin =
|
||||
Z_Malloc(
|
||||
sizeof(unloaded_skin_t),
|
||||
PU_STATIC, NULL
|
||||
);
|
||||
|
||||
// Establish properties, for later retrieval on file add.
|
||||
strlcpy(unloadedskin->name, skinname, sizeof(unloadedskin->name));
|
||||
unloadedskin->namehash = quickncasehash(unloadedskin->name, SKINNAMESIZE);
|
||||
|
||||
// Insert at the head, just because it's convenient.
|
||||
unloadedskin->next = unloadedskins;
|
||||
unloadedskins = unloadedskin;
|
||||
|
||||
// Finally, copy into.
|
||||
M_Memcpy(&unloadedskin->records, &dummyrecord, sizeof(skinrecord_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numgamedatamapheaders = READUINT32(save.p);
|
||||
|
||||
for (i = 0; i < numgamedatamapheaders; i++)
|
||||
|
|
@ -5157,6 +5223,36 @@ void G_SaveGameData(void)
|
|||
length += gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT;
|
||||
}
|
||||
|
||||
|
||||
UINT32 numgamedataskins = 0;
|
||||
unloaded_skin_t *unloadedskin;
|
||||
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
// It's safe to assume a skin with no wins will have no other data worth keeping
|
||||
if (skins[i].records.wins == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numgamedataskins++;
|
||||
}
|
||||
|
||||
for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next)
|
||||
{
|
||||
// Ditto, with the exception that we should warn about it.
|
||||
if (unloadedskin->records.wins == 0)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Unloaded skin \"%s\" has no wins!\n", unloadedskin->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
numgamedataskins++;
|
||||
}
|
||||
|
||||
length += 4 + (numgamedataskins * (SKINNAMESIZE+4));
|
||||
|
||||
|
||||
UINT32 numgamedatamapheaders = 0;
|
||||
unloaded_mapheader_t *unloadedmap;
|
||||
|
||||
|
|
@ -5313,6 +5409,42 @@ void G_SaveGameData(void)
|
|||
WRITEUINT32(save.p, gamedata->timesBeaten); // 4
|
||||
|
||||
// Main records
|
||||
|
||||
WRITEUINT32(save.p, numgamedataskins); // 4
|
||||
|
||||
{
|
||||
// numgamedataskins * (SKINNAMESIZE+4)
|
||||
|
||||
for (i = 0; i < numskins; i++)
|
||||
{
|
||||
if (skins[i].records.wins == 0)
|
||||
continue;
|
||||
|
||||
WRITESTRINGN(save.p, skins[i].name, SKINNAMESIZE);
|
||||
|
||||
WRITEUINT32(save.p, skins[i].records.wins);
|
||||
|
||||
if (--numgamedataskins == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (numgamedataskins)
|
||||
{
|
||||
for (unloadedskin = unloadedskins; unloadedskin; unloadedskin = unloadedskin->next)
|
||||
{
|
||||
if (unloadedskin->records.wins == 0)
|
||||
continue;
|
||||
|
||||
WRITESTRINGN(save.p, unloadedskin->name, SKINNAMESIZE);
|
||||
|
||||
WRITEUINT32(save.p, unloadedskin->records.wins);
|
||||
|
||||
if (--numgamedataskins == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WRITEUINT32(save.p, numgamedatamapheaders); // 4
|
||||
|
||||
if (numgamedatamapheaders)
|
||||
|
|
|
|||
|
|
@ -531,6 +531,8 @@ void M_ClearStats(void)
|
|||
gamedata->everseenspecial = false;
|
||||
gamedata->evercrashed = false;
|
||||
gamedata->musicflags = 0;
|
||||
|
||||
gamedata->importprofilewins = false;
|
||||
}
|
||||
|
||||
void M_ClearSecrets(void)
|
||||
|
|
|
|||
|
|
@ -282,6 +282,9 @@ struct gamedata_t
|
|||
boolean everseenspecial;
|
||||
boolean evercrashed;
|
||||
UINT8 musicflags;
|
||||
|
||||
// BACKWARDS COMPAT ASSIST
|
||||
boolean importprofilewins;
|
||||
};
|
||||
|
||||
extern gamedata_t *gamedata;
|
||||
|
|
|
|||
16
src/p_user.c
16
src/p_user.c
|
|
@ -1355,11 +1355,19 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
G_UpdateRecords();
|
||||
}
|
||||
|
||||
profile_t *pr = PR_GetPlayerProfile(player);
|
||||
if (pr != NULL && !losing)
|
||||
if (!losing)
|
||||
{
|
||||
pr->wins++;
|
||||
PR_SaveProfiles();
|
||||
profile_t *pr = PR_GetPlayerProfile(player);
|
||||
if (pr != NULL)
|
||||
{
|
||||
pr->wins++;
|
||||
PR_SaveProfiles();
|
||||
}
|
||||
|
||||
if (P_IsLocalPlayer(player) && player->skin < numskins)
|
||||
{
|
||||
skins[player->skin].records.wins++;
|
||||
}
|
||||
}
|
||||
|
||||
player->karthud[khud_cardanimation] = 0; // srb2kart: reset battle animation
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@
|
|||
INT32 numskins = 0;
|
||||
skin_t skins[MAXSKINS];
|
||||
|
||||
unloaded_skin_t *unloadedskins = NULL;
|
||||
|
||||
// FIXTHIS: don't work because it must be inistilised before the config load
|
||||
//#define SKINVALUES
|
||||
#ifdef SKINVALUES
|
||||
|
|
@ -125,6 +127,8 @@ static void Sk_SetDefaultValue(skin_t *skin)
|
|||
|
||||
skin->highresscale = FRACUNIT;
|
||||
|
||||
// no specific memset for skinrecord_t as it's already nuked by the full skin_t wipe
|
||||
|
||||
for (i = 0; i < sfx_skinsoundslot0; i++)
|
||||
if (S_sfx[i].skinsound != -1)
|
||||
skin->soundsid[S_sfx[i].skinsound] = i;
|
||||
|
|
@ -1006,6 +1010,38 @@ next_token:
|
|||
// Finally, conclude by setting up final properties.
|
||||
skin->namehash = quickncasehash(skin->name, SKINNAMESIZE);
|
||||
|
||||
{
|
||||
// Check to see if we have any custom skin wins data that we could substitute in.
|
||||
unloaded_skin_t *unloadedskin, *unloadedprev = NULL;
|
||||
for (unloadedskin = unloadedskins; unloadedskin; unloadedprev = unloadedskin, unloadedskin = unloadedskin->next)
|
||||
{
|
||||
if (unloadedskin->namehash != skin->namehash)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(skin->name, unloadedskin->name) != 0)
|
||||
continue;
|
||||
|
||||
// Copy in wins, etc.
|
||||
M_Memcpy(&skin->records, &unloadedskin->records, sizeof(skin->records));
|
||||
|
||||
// Remove this entry from the chain.
|
||||
if (unloadedprev)
|
||||
{
|
||||
unloadedprev->next = unloadedskin->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
unloadedskins = unloadedskin->next;
|
||||
}
|
||||
|
||||
// Finally, free.
|
||||
Z_Free(unloadedskin);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
numskins++;
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ extern "C" {
|
|||
#define DEFAULTSKIN3 "sonic" // third player
|
||||
#define DEFAULTSKIN4 "knuckles" // fourth player
|
||||
|
||||
struct skinrecord_t
|
||||
{
|
||||
UINT32 wins;
|
||||
};
|
||||
|
||||
/// The skin_t struct
|
||||
struct skin_t
|
||||
{
|
||||
|
|
@ -59,6 +64,8 @@ struct skin_t
|
|||
|
||||
fixed_t highresscale; // scale of highres, default is 0.5
|
||||
|
||||
skinrecord_t records;
|
||||
|
||||
char rivals[SKINRIVALS][SKINNAMESIZE+1]; // Your top 3 rivals for GP mode. Uses names so that you can reference skins that aren't added
|
||||
|
||||
// specific sounds per skin
|
||||
|
|
@ -69,6 +76,18 @@ struct skin_t
|
|||
spriteinfo_t sprinfo[NUMPLAYERSPRITES*2];
|
||||
};
|
||||
|
||||
struct unloaded_skin_t
|
||||
{
|
||||
char name[SKINNAMESIZE+1];
|
||||
UINT32 namehash;
|
||||
|
||||
skinrecord_t records;
|
||||
|
||||
unloaded_skin_t *next;
|
||||
};
|
||||
|
||||
extern unloaded_skin_t *unloadedskins;
|
||||
|
||||
enum facepatches {
|
||||
FACE_RANK = 0,
|
||||
FACE_WANTED,
|
||||
|
|
|
|||
|
|
@ -385,7 +385,9 @@ TYPEDEF (visffloor_t);
|
|||
TYPEDEF (portal_t);
|
||||
|
||||
// r_skins.h
|
||||
TYPEDEF (skinrecord_t);
|
||||
TYPEDEF (skin_t);
|
||||
TYPEDEF (unloaded_skin_t);
|
||||
|
||||
// r_splats.h
|
||||
TYPEDEF (floorsplat_t);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue