mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
cupwindata_t
Save your best GP stats across sessions.
- Saved into gamedata
- Deliniated per difficulty option
- Draw onto cupgrid in GP cup select
- Best grade
- Whether you've ever gotten the Emerald
- TODO: Always shows Chaos Emerald, will need updating when Super Emerald graphics are created
- Monitor status changes depending on recorded position
- 1st: Gold, shiny
- 2nd: Silver, shiny
- 3rd: Bronze, shiny
- 4th and downwards: Beige, barely different
- Wiped with G_ClearRecords
Also, to avoid circular dependencies:
- KARTSPEED/KARTGP constants moved from command.h to doomstat.h
- gp_rank_e enums moved from k_rank.h to doomstat.h
This commit is contained in:
parent
f3cde6140a
commit
dfe75726df
7 changed files with 226 additions and 36 deletions
|
|
@ -174,11 +174,7 @@ extern CV_PossibleValue_t CV_Unsigned[];
|
|||
extern CV_PossibleValue_t CV_Natural[];
|
||||
|
||||
// SRB2kart
|
||||
#define KARTSPEED_AUTO -1
|
||||
#define KARTSPEED_EASY 0
|
||||
#define KARTSPEED_NORMAL 1
|
||||
#define KARTSPEED_HARD 2
|
||||
#define KARTGP_MASTER 3 // Not a speed setting, gives the hardest speed with maxed out bots
|
||||
// the KARTSPEED and KARTGP were previously defined here, but moved to doomstat to avoid circular dependencies
|
||||
extern CV_PossibleValue_t kartspeed_cons_t[], dummykartspeed_cons_t[], gpdifficulty_cons_t[];
|
||||
|
||||
extern consvar_t cv_execversion;
|
||||
|
|
|
|||
|
|
@ -120,6 +120,30 @@ struct recorddata_t
|
|||
//UINT16 rings; ///< Rings when the level was finished.
|
||||
};
|
||||
|
||||
#define KARTSPEED_AUTO -1
|
||||
#define KARTSPEED_EASY 0
|
||||
#define KARTSPEED_NORMAL 1
|
||||
#define KARTSPEED_HARD 2
|
||||
#define KARTGP_MASTER 3 // Not a speed setting, gives the hardest speed with maxed out bots
|
||||
#define KARTGP_MAX 4
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GRADE_E,
|
||||
GRADE_D,
|
||||
GRADE_C,
|
||||
GRADE_B,
|
||||
GRADE_A,
|
||||
GRADE_S
|
||||
} gp_rank_e;
|
||||
|
||||
struct cupwindata_t
|
||||
{
|
||||
UINT8 best_placement;
|
||||
gp_rank_e best_grade;
|
||||
boolean got_emerald;
|
||||
};
|
||||
|
||||
// mapvisited is now a set of flags that says what we've done in the map.
|
||||
#define MV_VISITED (1)
|
||||
#define MV_BEATEN (1<<1)
|
||||
|
|
@ -358,6 +382,7 @@ struct cupheader_t
|
|||
UINT8 numlevels; ///< Number of levels defined in levellist
|
||||
UINT8 numbonus; ///< Number of bonus stages defined
|
||||
UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald)
|
||||
cupwindata_t windata[4]; ///< Data for cup visitation
|
||||
cupheader_t *next; ///< Next cup in linked list
|
||||
};
|
||||
|
||||
|
|
|
|||
81
src/g_game.c
81
src/g_game.c
|
|
@ -463,6 +463,8 @@ void G_AllocMainRecordData(INT16 i)
|
|||
void G_ClearRecords(void)
|
||||
{
|
||||
INT16 i;
|
||||
cupheader_t *cup;
|
||||
|
||||
for (i = 0; i < nummapheaders; ++i)
|
||||
{
|
||||
if (mapheaderinfo[i]->mainrecord)
|
||||
|
|
@ -471,6 +473,11 @@ void G_ClearRecords(void)
|
|||
mapheaderinfo[i]->mainrecord = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
memset(&cup->windata, 0, sizeof(cup->windata));
|
||||
}
|
||||
}
|
||||
|
||||
// For easy retrieval of records
|
||||
|
|
@ -4498,6 +4505,7 @@ void G_LoadGameData(void)
|
|||
|
||||
//For records
|
||||
UINT32 numgamedatamapheaders;
|
||||
UINT32 numgamedatacups;
|
||||
|
||||
// Stop saving, until we successfully load it again.
|
||||
gamedata->loaded = false;
|
||||
|
|
@ -4696,11 +4704,46 @@ void G_LoadGameData(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (versionMinor > 1)
|
||||
{
|
||||
numgamedatacups = READUINT32(save.p);
|
||||
|
||||
for (i = 0; i < numgamedatacups; i++)
|
||||
{
|
||||
char cupname[16];
|
||||
cupheader_t *cup;
|
||||
|
||||
READSTRINGN(save.p, cupname, sizeof(cupname));
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
if (strcmp(cup->name, cupname))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < KARTGP_MAX; j++)
|
||||
{
|
||||
rtemp = READUINT8(save.p);
|
||||
|
||||
cup->windata[j].best_placement = (rtemp & 0x0F);
|
||||
cup->windata[j].best_grade = (rtemp & 0x70)>>4;
|
||||
if (rtemp & 0x80)
|
||||
{
|
||||
if (j == 0)
|
||||
goto datacorrupt;
|
||||
|
||||
cup->windata[j].got_emerald = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
finalisegamedata:
|
||||
|
||||
{
|
||||
// Don't consider loaded until it's a success!
|
||||
// It used to do this much earlier, but this would cause the gamedata to
|
||||
// save over itself when it I_Errors from the corruption landing point below,
|
||||
|
|
@ -4711,6 +4754,7 @@ finalisegamedata:
|
|||
M_UpdateUnlockablesAndExtraEmblems(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Landing point for corrupt gamedata
|
||||
datacorrupt:
|
||||
|
|
@ -4730,7 +4774,8 @@ finalisegamedata:
|
|||
void G_SaveGameData(boolean dirty)
|
||||
{
|
||||
size_t length;
|
||||
INT32 i, j;
|
||||
INT32 i, j, numcups;
|
||||
cupheader_t *cup;
|
||||
UINT8 btemp;
|
||||
savebuffer_t save = {0};
|
||||
|
||||
|
|
@ -4752,12 +4797,20 @@ void G_SaveGameData(boolean dirty)
|
|||
4+1+1+1+1+
|
||||
1+1+4+
|
||||
(MAXEMBLEMS+(MAXUNLOCKABLES*2)+MAXCONDITIONSETS)+
|
||||
4+4+2);
|
||||
4+2);
|
||||
|
||||
if (gamedata->challengegrid)
|
||||
{
|
||||
length += gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT;
|
||||
}
|
||||
length += nummapheaders * (MAXMAPLUMPNAME+1+4+4);
|
||||
length += 4 + (nummapheaders * (MAXMAPLUMPNAME+1+4+4));
|
||||
|
||||
numcups = 0;
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
numcups++;
|
||||
}
|
||||
length += 4 + (numcups * 4);
|
||||
|
||||
if (P_SaveBufferAlloc(&save, length) == false)
|
||||
{
|
||||
|
|
@ -4851,7 +4904,7 @@ void G_SaveGameData(boolean dirty)
|
|||
|
||||
for (i = 0; i < nummapheaders; i++) // nummapheaders * (255+1+4+4)
|
||||
{
|
||||
// For figuring out which header to assing it to on load
|
||||
// For figuring out which header to assign it to on load
|
||||
WRITESTRINGN(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME);
|
||||
|
||||
WRITEUINT8(save.p, (mapheaderinfo[i]->mapvisited & MV_MAX));
|
||||
|
|
@ -4868,6 +4921,24 @@ void G_SaveGameData(boolean dirty)
|
|||
}
|
||||
}
|
||||
|
||||
WRITEUINT32(save.p, numcups); // 4
|
||||
|
||||
for (cup = kartcupheaders; cup; cup = cup->next)
|
||||
{
|
||||
// For figuring out which header to assign it to on load
|
||||
WRITESTRINGN(save.p, cup->name, 16);
|
||||
|
||||
for (i = 0; i < KARTGP_MAX; i++)
|
||||
{
|
||||
btemp = min(cup->windata[i].best_placement, 0x0F);
|
||||
btemp |= (cup->windata[i].best_grade<<4);
|
||||
if (i != 0 && cup->windata[i].got_emerald == true)
|
||||
btemp |= 0x80;
|
||||
|
||||
WRITEUINT8(save.p, btemp); // 4 * numcups
|
||||
}
|
||||
}
|
||||
|
||||
length = save.p - save.buffer;
|
||||
|
||||
FIL_WriteFile(va(pandf, srb2home, gamedatafilename), save.buffer, length);
|
||||
|
|
|
|||
|
|
@ -2113,6 +2113,8 @@ static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch)
|
|||
void M_DrawCupSelect(void)
|
||||
{
|
||||
UINT8 i, j, temp = 0;
|
||||
UINT8 *colormap = NULL;
|
||||
cupwindata_t *windata = NULL;
|
||||
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
|
||||
|
||||
for (i = 0; i < CUPMENU_COLUMNS; i++)
|
||||
|
|
@ -2123,26 +2125,62 @@ void M_DrawCupSelect(void)
|
|||
patch_t *patch = NULL;
|
||||
INT16 x, y;
|
||||
INT16 icony = 7;
|
||||
char status = 'A';
|
||||
UINT8 monitor = 1;
|
||||
INT32 rankx = 0;
|
||||
|
||||
if (!cupgrid.builtgrid[id])
|
||||
break;
|
||||
|
||||
templevelsearch.cup = cupgrid.builtgrid[id];
|
||||
|
||||
/*if (templevelsearch.cup->emeraldnum == 0)
|
||||
patch = W_CachePatchName("CUPMON3A", PU_CACHE);
|
||||
else*/ if (templevelsearch.cup->emeraldnum > 7)
|
||||
if (cupgrid.grandprix
|
||||
&& (cv_dummygpdifficulty.value >= 0 && cv_dummygpdifficulty.value < KARTGP_MAX))
|
||||
{
|
||||
patch = W_CachePatchName("CUPMON2A", PU_CACHE);
|
||||
icony = 5;
|
||||
UINT16 col = SKINCOLOR_NONE;
|
||||
|
||||
windata = &templevelsearch.cup->windata[cv_dummygpdifficulty.value];
|
||||
|
||||
switch (windata->best_placement)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
col = SKINCOLOR_GOLD;
|
||||
status = 'B';
|
||||
break;
|
||||
case 2:
|
||||
col = SKINCOLOR_SILVER;
|
||||
status = 'B';
|
||||
break;
|
||||
case 3:
|
||||
col = SKINCOLOR_BRONZE;
|
||||
status = 'B';
|
||||
break;
|
||||
default:
|
||||
col = SKINCOLOR_BEIGE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (col != SKINCOLOR_NONE)
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, col, GTC_MENUCACHE);
|
||||
else
|
||||
patch = W_CachePatchName("CUPMON1A", PU_CACHE);
|
||||
colormap = NULL;
|
||||
}
|
||||
|
||||
if (templevelsearch.cup->emeraldnum > 7)
|
||||
{
|
||||
monitor = 2;
|
||||
icony = 5;
|
||||
rankx = 2;
|
||||
}
|
||||
|
||||
patch = W_CachePatchName(va("CUPMON%d%c", monitor, status), PU_CACHE);
|
||||
|
||||
x = 14 + (i*42);
|
||||
y = 20 + (j*44) - (30*menutransition.tics);
|
||||
|
||||
V_DrawScaledPatch(x, y, 0, patch);
|
||||
V_DrawFixedPatch((x)*FRACUNIT, (y)<<FRACBITS, FRACUNIT, 0, patch, colormap);
|
||||
|
||||
if (M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID)
|
||||
{
|
||||
|
|
@ -2153,6 +2191,39 @@ void M_DrawCupSelect(void)
|
|||
{
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName(templevelsearch.cup->icon, PU_CACHE));
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName("CUPBOX", PU_CACHE));
|
||||
|
||||
if (!windata)
|
||||
;
|
||||
else if (windata->best_placement != 0)
|
||||
{
|
||||
char gradeChar = '?';
|
||||
|
||||
switch (windata->best_grade)
|
||||
{
|
||||
case GRADE_E: { gradeChar = 'E'; break; }
|
||||
case GRADE_D: { gradeChar = 'D'; break; }
|
||||
case GRADE_C: { gradeChar = 'C'; break; }
|
||||
case GRADE_B: { gradeChar = 'B'; break; }
|
||||
case GRADE_A: { gradeChar = 'A'; break; }
|
||||
case GRADE_S: { gradeChar = 'S'; break; }
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
V_DrawCharacter(x + 5 + rankx, y + icony + 14, gradeChar, false); // rank
|
||||
|
||||
if (windata->got_emerald == true)
|
||||
{
|
||||
if (templevelsearch.cup->emeraldnum == 0)
|
||||
V_DrawCharacter(x + 26 - rankx, y + icony + 14, '*', false); // rank
|
||||
else
|
||||
{
|
||||
UINT16 col = SKINCOLOR_CHAOSEMERALD1 + (templevelsearch.cup->emeraldnum-1) % 7;
|
||||
colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_MENUCACHE);
|
||||
|
||||
V_DrawFixedPatch((x + 26 - rankx)*FRACUNIT, (y + icony + 13)*FRACUNIT, FRACUNIT, 0, W_CachePatchName("K_EMERC", PU_CACHE), colormap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,6 +264,10 @@ void K_FinishCeremony(void)
|
|||
}
|
||||
|
||||
podiumData.ranking = true;
|
||||
|
||||
// Play the noise now
|
||||
M_UpdateUnlockablesAndExtraEmblems(true);
|
||||
G_SaveGameData(true);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -273,6 +277,8 @@ void K_FinishCeremony(void)
|
|||
--------------------------------------------------*/
|
||||
void K_ResetCeremony(void)
|
||||
{
|
||||
UINT8 i;
|
||||
|
||||
memset(&podiumData, 0, sizeof(struct podiumData_s));
|
||||
|
||||
if (K_PodiumSequence() == false)
|
||||
|
|
@ -280,8 +286,36 @@ void K_ResetCeremony(void)
|
|||
return;
|
||||
}
|
||||
|
||||
// Establish rank and grade for this play session.
|
||||
podiumData.rank = grandprixinfo.rank;
|
||||
podiumData.grade = K_CalculateGPGrade(&podiumData.rank);
|
||||
|
||||
if (!grandprixinfo.cup)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Write grade, position, and emerald-having-ness for later sessions!
|
||||
i = (grandprixinfo.masterbots) ? KARTGP_MASTER : grandprixinfo.gamespeed;
|
||||
|
||||
if ((grandprixinfo.cup->windata[i].best_placement == 0) // First run
|
||||
|| (podiumData.rank.position < grandprixinfo.cup->windata[i].best_placement)) // Later, better run
|
||||
{
|
||||
grandprixinfo.cup->windata[i].best_placement = podiumData.rank.position;
|
||||
|
||||
// The following will not occour in unmodified builds, but pre-emptively sanitise gamedata if someone just changes MAXPLAYERS and calls it a day
|
||||
if (grandprixinfo.cup->windata[i].best_placement > 0x0F)
|
||||
grandprixinfo.cup->windata[i].best_placement = 0x0F;
|
||||
}
|
||||
|
||||
if (podiumData.grade > grandprixinfo.cup->windata[i].best_grade)
|
||||
grandprixinfo.cup->windata[i].best_grade = podiumData.grade;
|
||||
|
||||
if (i != KARTSPEED_EASY && podiumData.rank.specialWon == true)
|
||||
grandprixinfo.cup->windata[i].got_emerald = true;
|
||||
|
||||
// Save before playing the noise
|
||||
G_SaveGameData(true);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
|
|||
10
src/k_rank.h
10
src/k_rank.h
|
|
@ -44,15 +44,7 @@ struct gpRank_t
|
|||
boolean specialWon;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GRADE_E,
|
||||
GRADE_D,
|
||||
GRADE_C,
|
||||
GRADE_B,
|
||||
GRADE_A,
|
||||
GRADE_S
|
||||
} gp_rank_e;
|
||||
// gp_rank_e was once defined here, but moved to doomstat.h to prevent circular dependency
|
||||
|
||||
// 3rd place is neutral, anything below is a penalty
|
||||
#define RANK_NEUTRAL_POSITION (3)
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ TYPEDEF (skincolor_t);
|
|||
// doomstat.h
|
||||
TYPEDEF (precipprops_t);
|
||||
TYPEDEF (recorddata_t);
|
||||
TYPEDEF (cupwindata_t);
|
||||
TYPEDEF (scene_t);
|
||||
TYPEDEF (cutscene_t);
|
||||
TYPEDEF (textpage_t);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue