Move two of the three remaining NUMMAPS arrays part of the mapheader_t struct

- mapvisited and recorddata_t (previously mainrecords)
- Changed how gamedata is saved and loaded
- Change the versioncheck (funny hex provided by chengi) AND call it `developringdata.dat` in develop builds
- Fix a bunch of off-by-ones in condition and emblem data
ALSO, for Time Attack:
- Fix menu not showing off your times
- Now save times even when gamedata modified, since the menu didn't care (come back to it?)
- Don't save times or do intermission screen if the Capsule Attack ended because you lost all your bumpers
- Fix a crash adding ghosts in Capsule Attack
This commit is contained in:
toaster 2022-09-21 22:12:36 +01:00
parent b8f3e64ca1
commit 60355d9efd
11 changed files with 179 additions and 106 deletions

View file

@ -2334,7 +2334,7 @@ void reademblemdata(MYFILE *f, INT32 num)
}
else if (fastcmp(word, "TAG"))
emblemlocations[num-1].tag = (INT16)value;
else if (fastcmp(word, "MAPNUM"))
else if (fastcmp(word, "MAPNAME"))
{
emblemlocations[num-1].level = Z_StrDup(word2);
}

View file

@ -105,6 +105,23 @@ extern preciptype_t precip_freeslot;
extern preciptype_t globalweather;
extern preciptype_t curWeather;
/** Time attack information, currently a very small structure.
*/
typedef struct
{
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.
} recorddata_t;
// 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_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE)
#define MV_MP ((MV_MAX+1)<<1)
// Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame;
extern boolean majormods;
@ -402,6 +419,10 @@ typedef struct
fixed_t mobj_scale; ///< Replacement for TOL_ERZ3
fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale
// Record data (modified liberally, saved to gamedata)
UINT8 mapvisited; ///< A set of flags that says what we've done in the map.
recorddata_t *mainrecord; ///< Stores best time attack data
// Lua stuff.
// (This is not ifdeffed so the map header structure can stay identical, just in case.)
UINT8 numCustomOptions; ///< Internal. For Lua custom value support.
@ -563,27 +584,6 @@ extern INT32 luabanks[NUM_LUABANKS];
extern INT32 nummaprings; //keep track of spawned rings/coins
/** Time attack information, currently a very small structure.
*/
typedef struct
{
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.
} recorddata_t;
//extern nightsdata_t *nightsrecords[NUMMAPS];
extern recorddata_t *mainrecords[NUMMAPS];
// 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_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE)
#define MV_MP ((MV_MAX+1)<<1)
extern UINT8 mapvisited[NUMMAPS];
extern UINT32 token; ///< Number of tokens collected in a level
extern UINT32 tokenlist; ///< List of tokens collected
extern boolean gottoken; ///< Did you get a token? Used for end of act

View file

@ -3358,7 +3358,7 @@ void G_AddGhost(char *defdemoname)
ghosts = gh;
gh->version = ghostversion;
mthing = playerstarts[0];
mthing = playerstarts[0] ? playerstarts[0] : deathmatchstarts[0]; // todo not correct but out of scope
I_Assert(mthing);
{ // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling.
fixed_t z,f,c;

View file

@ -75,7 +75,11 @@ JoyType_t Joystick[MAXSPLITSCREENPLAYERS];
#define SAVEGAMESIZE (1024)
// SRB2kart
char gamedatafilename[64] = "ringdata.dat";
char gamedatafilename[64] =
#ifdef DEVELOP
"develop"
#endif
"ringdata.dat";
char timeattackfolder[64] = "ringracers";
char customversionstring[32] = "\0";
@ -215,12 +219,6 @@ tic_t totalplaytime;
UINT32 matchesplayed; // SRB2Kart
boolean gamedataloaded = false;
// Time attack data for levels
// These are dynamically allocated for space reasons now
recorddata_t *mainrecords[NUMMAPS] = {NULL};
//nightsdata_t *nightsrecords[NUMMAPS] = {NULL};
UINT8 mapvisited[NUMMAPS];
// Temporary holding place for nights data for the current map
//nightsdata_t ntemprecords;
@ -473,21 +471,23 @@ INT32 player_name_changes[MAXPLAYERS];
// Allocation for time and nights data
void G_AllocMainRecordData(INT16 i)
{
if (!mainrecords[i])
mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL);
memset(mainrecords[i], 0, sizeof(recorddata_t));
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)
{
INT16 i;
for (i = 0; i < NUMMAPS; ++i)
for (i = 0; i < nummapheaders; ++i)
{
if (mainrecords[i])
if (mapheaderinfo[i]->mainrecord)
{
Z_Free(mainrecords[i]);
mainrecords[i] = NULL;
Z_Free(mapheaderinfo[i]->mainrecord);
mapheaderinfo[i]->mainrecord = NULL;
}
/*if (nightsrecords[i])
{
@ -500,20 +500,22 @@ void G_ClearRecords(void)
// For easy retrieval of records
tic_t G_GetBestTime(INT16 map)
{
if (!mainrecords[map-1] || mainrecords[map-1]->time <= 0)
if (!mapheaderinfo[map] || !mapheaderinfo[map]->mainrecord || mapheaderinfo[map]->mainrecord->time <= 0)
return (tic_t)UINT32_MAX;
return mainrecords[map-1]->time;
return mapheaderinfo[map]->mainrecord->time;
}
// BE RIGHT BACK
// Not needed
/*
tic_t G_GetBestLap(INT16 map)
{
if (!mainrecords[map-1] || mainrecords[map-1]->lap <= 0)
if (!mapheaderinfo[map] || !mapheaderinfo[map]->mainrecord || mapheaderinfo[map]->mainrecord->lap <= 0)
return (tic_t)UINT32_MAX;
return mainrecords[map-1]->lap;
return mapheaderinfo[map]->mainrecord->lap;
}
*/
@ -530,7 +532,7 @@ static void G_UpdateRecordReplays(void)
UINT8 earnedEmblems;
// Record new best time
if (!mainrecords[gamemap-1])
if (!mapheaderinfo[gamemap-1]->mainrecord)
G_AllocMainRecordData(gamemap-1);
if (players[consoleplayer].pflags & PF_NOCONTEST)
@ -538,20 +540,20 @@ static void G_UpdateRecordReplays(void)
players[consoleplayer].realtime = UINT32_MAX;
}
if (((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time))
if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (players[consoleplayer].realtime < mapheaderinfo[gamemap-1]->mainrecord->time))
&& (players[consoleplayer].realtime < UINT32_MAX)) // DNF
{
mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
mapheaderinfo[gamemap-1]->mainrecord->time = players[consoleplayer].realtime;
}
if (modeattacking == ATTACKING_TIME)
{
if ((mainrecords[gamemap-1]->lap == 0) || (bestlap < mainrecords[gamemap-1]->lap))
mainrecords[gamemap-1]->lap = bestlap;
if ((mapheaderinfo[gamemap-1]->mainrecord->lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->mainrecord->lap))
mapheaderinfo[gamemap-1]->mainrecord->lap = bestlap;
}
else
{
mainrecords[gamemap-1]->lap = 0;
mapheaderinfo[gamemap-1]->mainrecord->lap = 0;
}
// Save demo!
@ -3616,20 +3618,19 @@ void G_AddMapToBuffer(INT16 map)
//
static void G_UpdateVisited(void)
{
boolean spec = G_IsSpecialStage(gamemap);
// Update visitation flags?
if ((!modifiedgame || savemoddata) // Not modified
&& !multiplayer && !demo.playback // SP/RA/NiGHTS mode
&& !(spec && stagefailed)) // Not failed the special stage
if (/*(!majormods || savemoddata) // Not modified
&&*/ !multiplayer && !demo.playback // SP/RA/NiGHTS mode
&& !(modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST))) // Not failed
{
UINT8 earnedEmblems;
// Update visitation flags
mapvisited[gamemap-1] |= MV_BEATEN;
mapheaderinfo[gamemap-1]->mapvisited |= MV_BEATEN;
if (encoremode == true)
{
mapvisited[gamemap-1] |= MV_ENCORE;
mapheaderinfo[gamemap-1]->mapvisited |= MV_ENCORE;
}
if (modeattacking)
@ -3910,7 +3911,9 @@ static void G_DoCompleted(void)
// If the current gametype has no intermission screen set, then don't start it.
Y_DetermineIntermissionType();
if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed) || (intertype == int_none))
if ((skipstats && !modeattacking)
|| (modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST))
|| (intertype == int_none))
{
G_UpdateVisited();
G_HandleSaveLevel();
@ -4142,18 +4145,19 @@ void G_LoadGameSettings(void)
S_InitRuntimeSounds();
}
#define GD_VERSIONCHECK 0xBA5ED444
// G_LoadGameData
// Loads the main data file, which stores information such as emblems found, etc.
void G_LoadGameData(void)
{
size_t length;
INT32 i, j;
UINT32 i, j;
UINT8 modded = false;
UINT8 rtemp;
//For records
tic_t rectime;
tic_t reclap;
UINT32 numgamedatamapheaders;
// Clear things so previously read gamedata doesn't transfer
// to new gamedata
@ -4184,7 +4188,7 @@ void G_LoadGameData(void)
save_p = savebuffer;
// Version check
if (READUINT32(save_p) != 0xFCAFE211)
if (READUINT32(save_p) != GD_VERSIONCHECK)
{
const char *gdfolder = "the Ring Racers folder";
if (strcmp(srb2home,"."))
@ -4206,11 +4210,6 @@ void G_LoadGameData(void)
else if (modded != true && modded != false)
goto datacorrupt;
// TODO put another cipher on these things? meh, I don't care...
for (i = 0; i < NUMMAPS; i++)
if ((mapvisited[i] = READUINT8(save_p)) > MV_MAX)
goto datacorrupt;
// To save space, use one bit per collected/achieved/unlocked flag
for (i = 0; i < MAXEMBLEMS;)
{
@ -4244,16 +4243,44 @@ void G_LoadGameData(void)
timesBeaten = READUINT32(save_p);
// Main records
for (i = 0; i < NUMMAPS; ++i)
numgamedatamapheaders = READUINT32(save_p);
if (numgamedatamapheaders >= NEXTMAP_SPECIAL)
goto datacorrupt;
for (i = 0; i < numgamedatamapheaders; i++)
{
char mapname[255];
INT16 mapnum;
tic_t rectime;
tic_t reclap;
READSTRINGN(save_p, mapname, sizeof(mapname));
mapnum = G_MapNumber(mapname);
rtemp = READUINT8(save_p);
rectime = (tic_t)READUINT32(save_p);
reclap = (tic_t)READUINT32(save_p);
if (rectime || reclap)
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
{
G_AllocMainRecordData((INT16)i);
mainrecords[i]->time = rectime;
mainrecords[i]->lap = reclap;
// Valid mapheader, time to populate with record data.
if ((mapheaderinfo[mapnum]->mapvisited = rtemp) & ~MV_MAX)
goto datacorrupt;
if (rectime || reclap)
{
G_AllocMainRecordData((INT16)i);
mapheaderinfo[i]->mainrecord->time = rectime;
mapheaderinfo[i]->mainrecord->lap = reclap;
CONS_Printf("ID %d, Time = %d, Lap = %d\n", i, rectime/35, reclap/35);
}
}
else
{
// Since it's not worth declaring the entire gamedata
// corrupt over extra maps, we report and move on.
CONS_Alert(CONS_WARNING, "Map with lumpname %s does not exist, time record data will be discarded", mapname);
}
}
@ -4291,7 +4318,10 @@ void G_SaveGameData(void)
if (!gamedataloaded)
return; // If never loaded (-nodata), don't save
save_p = savebuffer = (UINT8 *)malloc(GAMEDATASIZE);
length = (4+4+4+1+(MAXEMBLEMS)+MAXEXTRAEMBLEMS+MAXUNLOCKABLES+MAXCONDITIONSETS+4+4);
length += nummapheaders * (255+1+4+4);
save_p = savebuffer = (UINT8 *)malloc(length);
if (!save_p)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
@ -4309,19 +4339,15 @@ void G_SaveGameData(void)
#endif
// Version test
WRITEUINT32(save_p, 0xFCAFE211);
WRITEUINT32(save_p, GD_VERSIONCHECK); // 4
WRITEUINT32(save_p, totalplaytime);
WRITEUINT32(save_p, matchesplayed);
WRITEUINT32(save_p, totalplaytime); // 4
WRITEUINT32(save_p, matchesplayed); // 4
WRITEUINT8(save_p, (UINT8)savemoddata);
// TODO put another cipher on these things? meh, I don't care...
for (i = 0; i < NUMMAPS; i++)
WRITEUINT8(save_p, (mapvisited[i] & MV_MAX));
WRITEUINT8(save_p, (UINT8)savemoddata); // 1
// To save space, use one bit per collected/achieved/unlocked flag
for (i = 0; i < MAXEMBLEMS;)
for (i = 0; i < MAXEMBLEMS;) // MAXEMBLEMS * 1;
{
btemp = 0;
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
@ -4329,7 +4355,7 @@ void G_SaveGameData(void)
WRITEUINT8(save_p, btemp);
i += j;
}
for (i = 0; i < MAXEXTRAEMBLEMS;)
for (i = 0; i < MAXEXTRAEMBLEMS;) // MAXEXTRAEMBLEMS * 1;
{
btemp = 0;
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
@ -4337,7 +4363,7 @@ void G_SaveGameData(void)
WRITEUINT8(save_p, btemp);
i += j;
}
for (i = 0; i < MAXUNLOCKABLES;)
for (i = 0; i < MAXUNLOCKABLES;) // MAXUNLOCKABLES * 1;
{
btemp = 0;
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
@ -4345,7 +4371,7 @@ void G_SaveGameData(void)
WRITEUINT8(save_p, btemp);
i += j;
}
for (i = 0; i < MAXCONDITIONSETS;)
for (i = 0; i < MAXCONDITIONSETS;) // MAXCONDITIONSETS * 1;
{
btemp = 0;
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
@ -4354,22 +4380,28 @@ void G_SaveGameData(void)
i += j;
}
WRITEUINT32(save_p, timesBeaten);
WRITEUINT32(save_p, timesBeaten); // 4
// Main records
for (i = 0; i < NUMMAPS; i++)
WRITEUINT32(save_p, nummapheaders); // 4
for (i = 0; i < nummapheaders; i++) // nummapheaders * (255+1+4+4)
{
if (mainrecords[i])
// For figuring out which header to assing it to on load
WRITESTRINGN(save_p, mapheaderinfo[i]->lumpname, 255);
WRITEUINT8(save_p, (mapheaderinfo[i]->mapvisited & MV_MAX));
if (mapheaderinfo[i]->mainrecord)
{
WRITEUINT32(save_p, mainrecords[i]->time);
WRITEUINT32(save_p, mainrecords[i]->lap);
WRITEUINT32(save_p, mapheaderinfo[i]->mainrecord->time);
WRITEUINT32(save_p, mapheaderinfo[i]->mainrecord->lap);
}
else
{
WRITEUINT32(save_p, 0);
WRITEUINT32(save_p, 0);
}
WRITEUINT8(save_p, 0); // compat
}
length = save_p - savebuffer;

View file

@ -23,7 +23,6 @@
extern char gamedatafilename[64];
extern char timeattackfolder[64];
extern char customversionstring[32];
#define GAMEDATASIZE (4*8192)
extern char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
extern INT32 player_name_changes[MAXPLAYERS];

View file

@ -17,6 +17,7 @@
#include "s_sound.h"
#include "m_random.h"
#include "r_sky.h" // skyflatnum
#include "k_grandprix.h" // K_CanChangeRules
// Battle overtime info
struct battleovertime battleovertime;
@ -126,7 +127,7 @@ void K_CheckBumpers(void)
winnerscoreadd -= players[i].roundscore;
}
if (bossinfo.boss)
if (K_CanChangeRules() == false)
{
if (nobumpers)
{

View file

@ -218,6 +218,15 @@ extern menu_t PLAY_LevelSelectDef;
extern menuitem_t PLAY_TimeAttack[];
extern menu_t PLAY_TimeAttackDef;
typedef enum
{
ta_replay = 0,
ta_guest,
ta_ghosts,
ta_spacer,
ta_start,
} ta_e;
extern menuitem_t PLAY_TAReplay[];
extern menu_t PLAY_TAReplayDef;

View file

@ -204,6 +204,7 @@ menu_t PLAY_LevelSelectDef = {
NULL
};
// see ta_e
menuitem_t PLAY_TimeAttack[] =
{
{IT_STRING | IT_SUBMENU, "Replay...", NULL, NULL, {.submenu = &PLAY_TAReplayDef}, 0, 0},

View file

@ -2159,19 +2159,34 @@ void M_DrawTimeAttack(void)
V_DrawScaledPatch(149+t, 70, 0, W_CachePatchName("BESTTIME", PU_CACHE));
if (currentMenu == &PLAY_TimeAttackDef)
if (currentMenu == &PLAY_TimeAttackDef && mapheaderinfo[map])
{
if (mapheaderinfo[map])
tic_t timerec = 0;
tic_t laprec = 0;
UINT32 timeheight = 82;
if ((minimap = mapheaderinfo[map]->minimapPic))
V_DrawScaledPatch(24-t, 82, 0, minimap);
if (mapheaderinfo[map]->mainrecord)
{
if ((minimap = mapheaderinfo[map]->minimapPic))
V_DrawScaledPatch(24-t, 82, 0, minimap);
timerec = mapheaderinfo[map]->mainrecord->time;
laprec = mapheaderinfo[map]->mainrecord->lap;
}
V_DrawRightAlignedString(rightedge-12, 82, highlightflags, "BEST LAP:");
K_drawKartTimestamp(0, 162+t, 88, 0, 2);
if (levellist.newgametype != GT_BATTLE)
{
V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:");
K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2);
timeheight += 30;
}
else
{
timeheight += 15;
}
V_DrawRightAlignedString(rightedge-12, 112, highlightflags, "BEST TIME:");
K_drawKartTimestamp(0, 162+t, 118, map, 1);
V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:");
K_drawKartTimestamp(timerec, 162+t, timeheight+6, map, 1);
}
else
opty = 80;

View file

@ -81,7 +81,10 @@ void M_ClearSecrets(void)
{
INT32 i;
memset(mapvisited, 0, sizeof(mapvisited));
for (i = 0; i < nummapheaders; ++i)
{
mapheaderinfo[i]->mapvisited = 0;
}
for (i = 0; i < MAXEMBLEMS; ++i)
emblemlocations[i].collected = false;
@ -129,11 +132,19 @@ UINT8 M_CheckCondition(condition_t *cn)
case UC_OVERALLTIME: // Requires overall time <= x
return (M_GotLowEnoughTime(cn->requirement));
case UC_MAPVISITED: // Requires map x to be visited
return ((mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED);
case UC_MAPBEATEN: // Requires map x to be beaten
return ((mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN);
case UC_MAPENCORE: // Requires map x to be beaten in encore
return ((mapvisited[cn->requirement - 1] & MV_ENCORE) == MV_ENCORE);
{
UINT8 mvtype = MV_VISITED;
if (cn->type == UC_MAPBEATEN)
mvtype = MV_BEATEN;
else if (cn->type == UC_MAPENCORE)
mvtype = MV_ENCORE;
return ((cn->requirement < nummapheaders)
&& (mapheaderinfo[cn->requirement])
&& ((mapheaderinfo[cn->requirement]->mapvisited & mvtype) == mvtype));
}
case UC_MAPTIME: // Requires time on map <= x
return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement);
case UC_TRIGGER: // requires map trigger set
@ -355,7 +366,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
if (embtype & ME_ENCORE)
flags |= MV_ENCORE;
res = ((mapvisited[levelnum - 1] & flags) == flags);
res = ((mapheaderinfo[levelnum]->mapvisited & flags) == flags);
emblemlocations[i].collected = res;
if (res)
@ -477,9 +488,9 @@ UINT8 M_GotLowEnoughTime(INT32 tictime)
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK))
continue;
if (!mainrecords[i] || !mainrecords[i]->time)
if (!mapheaderinfo[i]->mainrecord || !mapheaderinfo[i]->mainrecord->time)
return false;
else if ((curtics += mainrecords[i]->time) > tictime)
else if ((curtics += mapheaderinfo[i]->mainrecord->time) > tictime)
return false;
}
return true;

View file

@ -408,6 +408,10 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
P_DeleteFlickies(num);
#endif
mapheaderinfo[num]->mapvisited = 0;
Z_Free(mapheaderinfo[num]->mainrecord);
mapheaderinfo[num]->mainrecord = NULL;
mapheaderinfo[num]->customopts = NULL;
mapheaderinfo[num]->numCustomOptions = 0;
}
@ -426,6 +430,7 @@ void P_AllocMapHeader(INT16 i)
mapheaderinfo[i]->thumbnailPic = NULL;
mapheaderinfo[i]->minimapPic = NULL;
mapheaderinfo[i]->flickies = NULL;
mapheaderinfo[i]->mainrecord = NULL;
nummapheaders++;
}
P_ClearSingleMapHeaderInfo(i + 1);
@ -4265,9 +4270,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
skipstats = 0;
if (!(netgame || multiplayer || demo.playback) && !majormods)
mapvisited[gamemap-1] |= MV_VISITED;
mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED;
else if (!demo.playback)
mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently
mapheaderinfo[gamemap-1]->mapvisited |= MV_MP; // you want to record that you've been there this session, but not permanently
G_AddMapToBuffer(gamemap-1);