recorddata_t handling adjustments

Preperatory work for the next feature on my agenda.
- No longer independently allocated.
    - This was a byproduct of the previous NUMMAPS-based implementation. It's just cleaner to have it live directly on the mapheader_t, no caveats about it.
- Now contains mapvisited bitflag array.
    - Now all to-gamedata properties on a mapheader's struct are grouped together.
        - I was of two minds about it, but decided that this would have cleaner guarantees for compartmentalisation, saving, and loading.
        - They can still be wiped independently (G_ClearRecords for time/lap and M_ClearSecrets for mapvisited).
This commit is contained in:
toaster 2023-05-24 00:18:12 +01:00
parent 533508d7b0
commit 4c34d04f8a
10 changed files with 46 additions and 83 deletions

View file

@ -192,8 +192,6 @@ void clear_levels(void)
P_DeleteHeaderFollowers(nummapheaders);
Z_Free(mapheaderinfo[nummapheaders]->mainrecord);
Patch_Free(mapheaderinfo[nummapheaders]->thumbnailPic);
Patch_Free(mapheaderinfo[nummapheaders]->minimapPic);

View file

@ -112,12 +112,19 @@ extern preciptype_t curWeather;
/** Time attack information, currently a very small structure.
*/
// 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)
#define MV_ENCORE (1<<2)
#define MV_SPBATTACK (1<<3)
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK)
struct recorddata_t
{
UINT8 mapvisited;
tic_t time; ///< Time in which the level was finished.
tic_t lap; ///< Best lap time for this level.
//UINT32 score; ///< Score when the level was finished.
//UINT16 rings; ///< Rings when the level was finished.
};
#define KARTSPEED_AUTO -1
@ -144,14 +151,6 @@ struct cupwindata_t
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)
#define MV_ENCORE (1<<2)
#define MV_SPBATTACK (1<<3)
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK)
#define MV_MP ((MV_MAX+1)<<1)
// Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame;
extern boolean majormods;
@ -417,8 +416,7 @@ struct mapheader_t
UINT8 ghostCount; ///< Count of valid staff ghosts
staffbrief_t *ghostBrief[MAXSTAFF]; ///< Mallocated array of names for each staff ghost
UINT8 mapvisited; ///< A set of flags that says what we've done in the map.
recorddata_t *mainrecord; ///< Stores best time attack data
recorddata_t records; ///< Stores completion/record attack data
cupheader_t *cup; ///< Cached cup

View file

@ -444,16 +444,6 @@ consvar_t cv_rumble[MAXSPLITSCREENPLAYERS] = {
char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
INT32 player_name_changes[MAXPLAYERS];
// Allocation for time and nights data
void G_AllocMainRecordData(INT16 i)
{
if (i > nummapheaders || !mapheaderinfo[i])
I_Error("G_AllocMainRecordData: Internal map ID %d not found (nummapheaders = %d)\n", i, nummapheaders);
if (!mapheaderinfo[i]->mainrecord)
mapheaderinfo[i]->mainrecord = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL);
memset(mapheaderinfo[i]->mainrecord, 0, sizeof(recorddata_t));
}
// MAKE SURE YOU SAVE DATA BEFORE CALLING THIS
void G_ClearRecords(void)
{
@ -462,11 +452,8 @@ void G_ClearRecords(void)
for (i = 0; i < nummapheaders; ++i)
{
if (mapheaderinfo[i]->mainrecord)
{
Z_Free(mapheaderinfo[i]->mainrecord);
mapheaderinfo[i]->mainrecord = NULL;
}
mapheaderinfo[i]->records.time = 0;
mapheaderinfo[i]->records.lap = 0;
}
for (cup = kartcupheaders; cup; cup = cup->next)
@ -478,10 +465,10 @@ void G_ClearRecords(void)
// For easy retrieval of records
tic_t G_GetBestTime(INT16 map)
{
if (!mapheaderinfo[map] || !mapheaderinfo[map]->mainrecord || mapheaderinfo[map]->mainrecord->time <= 0)
if (!mapheaderinfo[map] || mapheaderinfo[map]->records.time <= 0)
return (tic_t)UINT32_MAX;
return mapheaderinfo[map]->mainrecord->time;
return mapheaderinfo[map]->records.time;
}
// BE RIGHT BACK
@ -490,10 +477,10 @@ tic_t G_GetBestTime(INT16 map)
/*
tic_t G_GetBestLap(INT16 map)
{
if (!mapheaderinfo[map] || !mapheaderinfo[map]->mainrecord || mapheaderinfo[map]->mainrecord->lap <= 0)
if (!mapheaderinfo[map] || mapheaderinfo[map]->records.lap <= 0)
return (tic_t)UINT32_MAX;
return mapheaderinfo[map]->mainrecord->lap;
return mapheaderinfo[map]->records.lap;
}
*/
@ -621,32 +608,28 @@ void G_UpdateRecords(void)
{
UINT8 earnedEmblems;
// Record new best time
if (!mapheaderinfo[gamemap-1]->mainrecord)
G_AllocMainRecordData(gamemap-1);
if (modeattacking & ATTACKING_TIME)
{
tic_t time = players[consoleplayer].realtime;
if (players[consoleplayer].pflags & PF_NOCONTEST)
time = UINT32_MAX;
if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (time < mapheaderinfo[gamemap-1]->mainrecord->time))
if (((mapheaderinfo[gamemap-1]->records.time == 0) || (time < mapheaderinfo[gamemap-1]->records.time))
&& (time < UINT32_MAX)) // DNF
mapheaderinfo[gamemap-1]->mainrecord->time = time;
mapheaderinfo[gamemap-1]->records.time = time;
}
else
{
mapheaderinfo[gamemap-1]->mainrecord->time = 0;
mapheaderinfo[gamemap-1]->records.time = 0;
}
if (modeattacking & ATTACKING_LAP)
{
if ((mapheaderinfo[gamemap-1]->mainrecord->lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->mainrecord->lap))
mapheaderinfo[gamemap-1]->mainrecord->lap = bestlap;
if ((mapheaderinfo[gamemap-1]->records.lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->records.lap))
mapheaderinfo[gamemap-1]->records.lap = bestlap;
}
else
{
mapheaderinfo[gamemap-1]->mainrecord->lap = 0;
mapheaderinfo[gamemap-1]->records.lap = 0;
}
// Check emblems when level data is updated
@ -3986,16 +3969,16 @@ static void G_UpdateVisited(void)
return;
// Update visitation flags
mapheaderinfo[prevmap]->mapvisited |= MV_BEATEN;
mapheaderinfo[prevmap]->records.mapvisited |= MV_BEATEN;
if (encoremode == true)
{
mapheaderinfo[prevmap]->mapvisited |= MV_ENCORE;
mapheaderinfo[prevmap]->records.mapvisited |= MV_ENCORE;
}
if (modeattacking & ATTACKING_SPB)
{
mapheaderinfo[prevmap]->mapvisited |= MV_SPBATTACK;
mapheaderinfo[prevmap]->records.mapvisited |= MV_SPBATTACK;
}
if (modeattacking)
@ -4959,14 +4942,13 @@ void G_LoadGameData(void)
{
// Valid mapheader, time to populate with record data.
if ((mapheaderinfo[mapnum]->mapvisited = rtemp) & ~MV_MAX)
if ((mapheaderinfo[mapnum]->records.mapvisited = rtemp) & ~MV_MAX)
goto datacorrupt;
if (rectime || reclap)
{
G_AllocMainRecordData((INT16)i);
mapheaderinfo[i]->mainrecord->time = rectime;
mapheaderinfo[i]->mainrecord->lap = reclap;
mapheaderinfo[i]->records.time = rectime;
mapheaderinfo[i]->records.lap = reclap;
//CONS_Printf("ID %d, Time = %d, Lap = %d\n", i, rectime/35, reclap/35);
}
}
@ -5219,18 +5201,10 @@ void G_SaveGameData(void)
// 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));
WRITEUINT8(save.p, (mapheaderinfo[i]->records.mapvisited & MV_MAX));
if (mapheaderinfo[i]->mainrecord)
{
WRITEUINT32(save.p, mapheaderinfo[i]->mainrecord->time);
WRITEUINT32(save.p, mapheaderinfo[i]->mainrecord->lap);
}
else
{
WRITEUINT32(save.p, 0);
WRITEUINT32(save.p, 0);
}
WRITEUINT32(save.p, mapheaderinfo[i]->records.time);
WRITEUINT32(save.p, mapheaderinfo[i]->records.lap);
}
WRITEUINT32(save.p, numcups); // 4

View file

@ -264,7 +264,6 @@ void G_SetGameModified(boolean silent, boolean major);
void G_SetUsedCheats(void);
// Gamedata record shit
void G_AllocMainRecordData(INT16 i);
void G_ClearRecords(void);
tic_t G_GetBestTime(INT16 map);

View file

@ -2640,11 +2640,8 @@ void M_DrawTimeAttack(void)
if ((minimap = mapheaderinfo[map]->minimapPic))
V_DrawScaledPatch(24-t, 82, 0, minimap);
if (mapheaderinfo[map]->mainrecord)
{
timerec = mapheaderinfo[map]->mainrecord->time;
laprec = mapheaderinfo[map]->mainrecord->lap;
}
timerec = mapheaderinfo[map]->records.time;
laprec = mapheaderinfo[map]->records.lap;
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
&& (mapheaderinfo[map]->numlaps != 1))
@ -5779,13 +5776,13 @@ void M_DrawStatistics(void)
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU)))
continue;
if (!mapheaderinfo[i]->mainrecord || mapheaderinfo[i]->mainrecord->time <= 0)
if (mapheaderinfo[i]->records.time <= 0)
{
mapsunfinished++;
continue;
}
besttime += mapheaderinfo[i]->mainrecord->time;
besttime += mapheaderinfo[i]->records.time;
}
V_DrawThinString(20, 60, V_6WIDTHSPACE|V_ALLOWLOWERCASE, "Combined time records:");

View file

@ -539,7 +539,7 @@ void M_ClearSecrets(void)
for (i = 0; i < nummapheaders; ++i)
{
mapheaderinfo[i]->mapvisited = 0;
mapheaderinfo[i]->records.mapvisited = 0;
}
for (i = 0; i < MAXEMBLEMS; ++i)
@ -702,7 +702,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
return ((cn->requirement < nummapheaders)
&& (mapheaderinfo[cn->requirement])
&& ((mapheaderinfo[cn->requirement]->mapvisited & mvtype) == mvtype));
&& ((mapheaderinfo[cn->requirement]->records.mapvisited & mvtype) == mvtype));
}
case UC_MAPTIME: // Requires time on map <= x
return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement);
@ -932,7 +932,7 @@ static char *M_BuildConditionTitle(UINT16 map)
if (((mapheaderinfo[map]->menuflags & LF2_FINISHNEEDED)
// the following is intentionally not MV_BEATEN, just in case the title is for "Finish a round on X"
&& !(mapheaderinfo[map]->mapvisited & MV_VISITED))
&& !(mapheaderinfo[map]->records.mapvisited & MV_VISITED))
|| M_MapLocked(map+1))
return Z_StrDup("???");
@ -1770,7 +1770,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
if (embtype & ME_SPBATTACK)
flags |= MV_SPBATTACK;
res = ((mapheaderinfo[levelnum]->mapvisited & flags) == flags);
res = ((mapheaderinfo[levelnum]->records.mapvisited & flags) == flags);
gamedata->collected[i] = res;
if (res)
@ -1955,9 +1955,9 @@ UINT8 M_GotLowEnoughTime(INT32 tictime)
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK))
continue;
if (!mapheaderinfo[i]->mainrecord || !mapheaderinfo[i]->mainrecord->time)
if (!mapheaderinfo[i]->records.time)
return false;
else if ((curtics += mapheaderinfo[i]->mainrecord->time) > tictime)
if ((curtics += mapheaderinfo[i]->records.time) > tictime)
return false;
}
return true;

View file

@ -26,7 +26,7 @@ static boolean M_StatisticsAddMap(UINT16 map, cupheader_t *cup, boolean *headere
// Check for completion
if ((mapheaderinfo[map]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[map]->mapvisited & MV_BEATEN))
&& !(mapheaderinfo[map]->records.mapvisited & MV_BEATEN))
return false;
// Check for unlock

View file

@ -88,7 +88,7 @@ boolean M_CanShowLevelInList(INT16 mapnum, levelsearch_t *levelsearch)
{
// Check for completion
if ((mapheaderinfo[mapnum]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[mapnum]->mapvisited & MV_BEATEN))
&& !(mapheaderinfo[mapnum]->records.mapvisited & MV_BEATEN))
return false;
// Check for unlock

View file

@ -446,9 +446,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 num)
P_DeleteHeaderFollowers(num);
#endif
mapheaderinfo[num]->mapvisited = 0;
Z_Free(mapheaderinfo[num]->mainrecord);
mapheaderinfo[num]->mainrecord = NULL;
memset(&mapheaderinfo[num]->records, 0, sizeof(recorddata_t));
mapheaderinfo[num]->justPlayed = 0;
mapheaderinfo[num]->anger = 0;
@ -506,7 +504,6 @@ void P_AllocMapHeader(INT16 i)
mapheaderinfo[i]->minimapPic = NULL;
mapheaderinfo[i]->ghostCount = 0;
mapheaderinfo[i]->cup = NULL;
mapheaderinfo[i]->mainrecord = NULL;
mapheaderinfo[i]->followers = NULL;
nummapheaders++;
}
@ -8312,7 +8309,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
if (!demo.playback)
{
mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED;
mapheaderinfo[gamemap-1]->records.mapvisited |= MV_VISITED;
M_UpdateUnlockablesAndExtraEmblems(true, true);
G_SaveGameData();

View file

@ -1534,7 +1534,7 @@ static boolean S_SoundTestDefLocked(musicdef_t *def)
// Is the level tied to SP progression?
if ((mapheaderinfo[def->sequence.map]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[def->sequence.map]->mapvisited & MV_BEATEN))
&& !(mapheaderinfo[def->sequence.map]->records.mapvisited & MV_BEATEN))
return true;
// Finally, do a full-fat map check.