Rewrite random map buffer

Each map now just has a countdown for when they'll reappear (stored in mapheader), which gets decremented each time a new map is played. This means it's now compatible across gametype switches, is a lot less complex, and is easy to retrieve the value for a specific map without needing to iterate constantly.

Lots of the old unused code surrounding this function was also removed. Lastly, added a PARANOIA check for callAgainSoon being mishandled.
This commit is contained in:
Sally Coolatta 2023-04-04 23:22:12 -04:00
parent b799862ccb
commit 81871bc73b
7 changed files with 123 additions and 150 deletions

View file

@ -2617,15 +2617,23 @@ void D_SetupVote(void)
{ {
UINT8 buf[(VOTE_NUM_LEVELS * 2) + 2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes UINT8 buf[(VOTE_NUM_LEVELS * 2) + 2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes
UINT8 *p = buf; UINT8 *p = buf;
INT32 i; INT32 i;
INT16 votebuffer[VOTE_NUM_LEVELS] = {-1};
INT16 votebuffer[VOTE_NUM_LEVELS + 1] = {-1};
votebuffer[VOTE_NUM_LEVELS] = 0; // End marker for G_RandMap
WRITEUINT8(p, ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE))); WRITEUINT8(p, ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE)));
WRITEUINT8(p, G_SometimesGetDifferentEncore()); WRITEUINT8(p, G_SometimesGetDifferentEncore());
for (i = 0; i < VOTE_NUM_LEVELS; i++) for (i = 0; i < VOTE_NUM_LEVELS; i++)
{ {
UINT16 m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer); UINT16 m = G_RandMap(
G_TOLFlag(gametype),
prevmap, false,
(i < VOTE_NUM_LEVELS-1),
votebuffer
);
votebuffer[i] = m; votebuffer[i] = m;
WRITEUINT16(p, m); WRITEUINT16(p, m);
} }
@ -3202,7 +3210,7 @@ static void Command_RandomMap(void)
oldmapnum = -1; oldmapnum = -1;
} }
newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, 0, 0, false, NULL) + 1; newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, false, false, NULL) + 1;
D_MapChange(newmapnum, newgametype, newencore, newresetplayers, 0, false, false); D_MapChange(newmapnum, newgametype, newencore, newresetplayers, 0, false, false);
} }

View file

@ -410,6 +410,8 @@ struct mapheader_t
cupheader_t *cup; ///< Cached cup cupheader_t *cup; ///< Cached cup
size_t justPlayed; ///< Prevent this map from showing up in votes if it was recently picked.
// Titlecard information // Titlecard information
char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway)
char subttl[33]; ///< Subtitle for level char subttl[33]; ///< Subtitle for level

View file

@ -2250,7 +2250,7 @@ void F_TitleScreenTicker(boolean run)
// prevent console spam if failed // prevent console spam if failed
demoIdleLeft = demoIdleTime; demoIdleLeft = demoIdleTime;
mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, 2, 0, false, NULL); mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, true, false, NULL);
if (mapnum == 0) // gotta have ONE if (mapnum == 0) // gotta have ONE
{ {
return; return;

View file

@ -319,23 +319,6 @@ boolean comebackshowninfo; // Have you already seen the "ATTACK OR PROTECT" mess
tic_t curlap; // Current lap time tic_t curlap; // Current lap time
tic_t bestlap; // Best lap time tic_t bestlap; // Best lap time
typedef struct
{
INT16 *mapbuffer; // Pointer to zone memory
INT32 lastnummapheaders; // Reset if nummapheaders != this
} randmaps_t;
static randmaps_t randmaps = {NULL, 0};
static void G_ResetRandMapBuffer(void)
{
INT32 i;
Z_Free(randmaps.mapbuffer);
randmaps.lastnummapheaders = nummapheaders;
randmaps.mapbuffer = Z_Malloc(randmaps.lastnummapheaders * sizeof(INT16), PU_STATIC, NULL);
for (i = 0; i < randmaps.lastnummapheaders; i++)
randmaps.mapbuffer[i] = -1;
}
typedef struct joystickvector2_s typedef struct joystickvector2_s
{ {
INT32 xaxis; INT32 xaxis;
@ -3726,188 +3709,170 @@ static INT32 TOLMaps(UINT8 pgametype)
* has those flags. * has those flags.
* \author Graue <graue@oceanbase.org> * \author Graue <graue@oceanbase.org>
*/ */
static INT16 *okmaps = NULL; static INT16 *g_allowedMaps = NULL;
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer)
#ifdef PARANOIA
static INT32 g_randMapStack = 0;
#endif
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, INT16 *extBuffer)
{ {
UINT32 numokmaps = 0; INT32 allowedMapsCount = 0;
INT16 ix, bufx; INT32 extBufferCount = 0;
UINT16 extbufsize = 0; INT16 ret = 0;
INT32 i, j;
if (randmaps.lastnummapheaders != nummapheaders) #ifdef PARANOIA
g_randMapStack++;
#endif
if (g_allowedMaps == NULL)
{ {
G_ResetRandMapBuffer(); g_allowedMaps = Z_Malloc(nummapheaders * sizeof(INT16), PU_STATIC, NULL);
} }
if (!okmaps) if (extBuffer != NULL)
{ {
//CONS_Printf("(making okmaps)\n"); for (i = 0; extBuffer[i] != 0; i++)
okmaps = Z_Malloc(nummapheaders * sizeof(INT16), PU_STATIC, NULL);
}
if (extbuffer != NULL)
{ {
bufx = 0; extBufferCount++;
while (extbuffer[bufx])
{
extbufsize++;
bufx++;
} }
} }
tryagain: tryAgain:
// Find all the maps that are ok and and put them in an array. for (i = 0; i < nummapheaders; i++)
for (ix = 0; ix < nummapheaders; ix++)
{ {
boolean isokmap = true; if (mapheaderinfo[i] == NULL || mapheaderinfo[i]->lumpnum == LUMPERROR)
if (!mapheaderinfo[ix] || mapheaderinfo[ix]->lumpnum == LUMPERROR)
{ {
// Doesn't exist?
continue; continue;
} }
if (!(mapheaderinfo[ix]->typeoflevel & tolflags) if (i == pprevmap)
|| ix == pprevmap
|| M_MapLocked(ix+1)
|| (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU)) // this is bad
{ {
continue; //isokmap = false; // We were just here.
continue;
}
if ((mapheaderinfo[i]->typeoflevel & tolflags) == 0)
{
// Doesn't match our gametype.
continue;
} }
if (pprevmap == -2 // title demo hack if (pprevmap == -2 // title demo hack
&& mapheaderinfo[ix]->ghostCount == 0) && mapheaderinfo[i]->ghostCount == 0)
{ {
// Doesn't have any ghosts, so it's not suitable for title demos.
continue; continue;
} }
if (!ignorebuffer) if ((mapheaderinfo[i]->menuflags & LF2_HIDEINMENU) == LF2_HIDEINMENU)
{ {
if (extbufsize > 0) // Not intended to be accessed in multiplayer.
{
for (bufx = 0; bufx < extbufsize; bufx++)
{
if (extbuffer[bufx] == -1) // Rest of buffer SHOULD be empty
{
break;
}
if (ix == extbuffer[bufx])
{
isokmap = false;
break;
}
}
if (!isokmap)
{
continue;
}
}
for (bufx = 0; bufx < (maphell ? 3 : randmaps.lastnummapheaders); bufx++)
{
if (randmaps.mapbuffer[bufx] == -1) // Rest of buffer SHOULD be empty
{
break;
}
if (ix == randmaps.mapbuffer[bufx])
{
isokmap = false;
break;
}
}
if (!isokmap)
continue; continue;
} }
okmaps[numokmaps++] = ix; if (M_MapLocked(i + 1) == true)
{
// We haven't earned this one.
continue;
} }
if (numokmaps == 0) // If there's no matches... (Goodbye, incredibly silly function chains :V) if (ignoreBuffers == false)
{ {
if (!ignorebuffer) if (mapheaderinfo[i]->justPlayed > 0)
{ {
if (randmaps.mapbuffer[VOTE_NUM_LEVELS] == -1) // Is the buffer basically empty? // We just played this map, don't play it again.
{ continue;
ignorebuffer = 1; // This will probably only help in situations where there's very few maps, but it's folly not to at least try it
//CONS_Printf("RANDMAP - ignoring buffer\n");
goto tryagain;
} }
for (bufx = VOTE_NUM_LEVELS; bufx < randmaps.lastnummapheaders; bufx++) // Let's clear all but the three most recent maps... if (extBufferCount > 0)
{ {
randmaps.mapbuffer[bufx] = -1; // An optional additional buffer,
// to avoid duplicates on the voting screen.
for (j = 0; j < extBufferCount; j++)
{
if (extBuffer[j] < 0 || extBuffer[j] >= nummapheaders)
{
// Rest of buffer SHOULD be empty.
break;
} }
//CONS_Printf("RANDMAP - emptying randmapbuffer\n"); if (i == extBuffer[j])
goto tryagain; {
// Map is in this other buffer, don't duplicate.
break;
}
} }
//CONS_Printf("RANDMAP - defaulting to map01\n"); if (j < extBufferCount)
ix = 0; // Sorry, none match. You get MAP01. {
// Didn't make it out of this buffer, so don't add this map.
continue;
}
}
}
if (ignorebuffer == 1) // Got past the gauntlet, so we can allow this one.
{ g_allowedMaps[ allowedMapsCount++ ] = i;
//CONS_Printf("(emptying randmapbuffer entirely)\n");
for (bufx = 0; bufx < randmaps.lastnummapheaders; bufx++)
{
randmaps.mapbuffer[bufx] = -1; // if we're having trouble finding a map we should probably clear it
} }
if (allowedMapsCount == 0)
{
// No maps are available.
if (ignoreBuffers == false)
{
// Try again with ignoring the buffer before giving up.
ignoreBuffers = true;
goto tryAgain;
} }
// Nothing else actually worked. Welp!
// You just get whatever was added first.
ret = 0;
} }
else else
{ {
//CONS_Printf("RANDMAP - %d maps available to grab\n", numokmaps); ret = g_allowedMaps[ M_RandomKey(allowedMapsCount) ];
ix = okmaps[M_RandomKey(numokmaps)];
} }
if (!callagainsoon) if (callAgainSoon == false)
{ {
//CONS_Printf("(freeing okmaps)\n"); Z_Free(g_allowedMaps);
Z_Free(okmaps); g_allowedMaps = NULL;
okmaps = NULL;
#ifdef PARANOIA
// Crash if callAgainSoon was mishandled.
I_Assert(g_randMapStack == 1);
#endif
} }
return ix; #ifdef PARANOIA
g_randMapStack--;
#endif
return ret;
} }
void G_AddMapToBuffer(INT16 map) void G_AddMapToBuffer(INT16 map)
{ {
INT16 bufx; if (mapheaderinfo[map]->justPlayed == 0) // Started playing a new map.
INT16 refreshnum = (TOLMaps(gametype)) - VOTE_NUM_LEVELS;
if (refreshnum < 0)
{ {
refreshnum = 0; // Decrement every maps' justPlayed value.
INT32 i;
for (i = 0; i < nummapheaders; i++)
{
if (mapheaderinfo[i]->justPlayed > 0)
{
mapheaderinfo[i]->justPlayed--;
} }
if (nummapheaders != randmaps.lastnummapheaders)
{
G_ResetRandMapBuffer();
}
else
{
for (bufx = randmaps.lastnummapheaders - 1; bufx > 0; bufx--)
{
randmaps.mapbuffer[bufx] = randmaps.mapbuffer[bufx-1];
} }
} }
randmaps.mapbuffer[0] = map; // Set our map's justPlayed value.
mapheaderinfo[map]->justPlayed = TOLMaps(gametype) - VOTE_NUM_LEVELS;
// We're getting pretty full, so lets flush this for future usage.
if (randmaps.mapbuffer[refreshnum] != -1)
{
// Clear all but the most recent maps.
for (bufx = VOTE_NUM_LEVELS; bufx < randmaps.lastnummapheaders; bufx++)
{
randmaps.mapbuffer[bufx] = -1;
}
//CONS_Printf("Random map buffer has been flushed.\n");
}
} }
// //
@ -4234,7 +4199,7 @@ static void G_GetNextMap(void)
} }
/* FALLTHRU */ /* FALLTHRU */
case 2: // Go to random map. case 2: // Go to random map.
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, false, NULL);
break; break;
default: default:
if (nextmap >= NEXTMAP_SPECIAL) // Loop back around if (nextmap >= NEXTMAP_SPECIAL) // Loop back around
@ -5394,8 +5359,6 @@ void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ss
G_FreeGhosts(); // TODO: do we actually need to do this? G_FreeGhosts(); // TODO: do we actually need to do this?
G_ResetRandMapBuffer();
// this leave the actual game if needed // this leave the actual game if needed
SV_StartSinglePlayerServer(gametype, false); SV_StartSinglePlayerServer(gametype, false);

View file

@ -255,7 +255,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics);
UINT32 G_TOLFlag(INT32 pgametype); UINT32 G_TOLFlag(INT32 pgametype);
INT16 G_GetFirstMapOfGametype(UINT8 pgametype); INT16 G_GetFirstMapOfGametype(UINT8 pgametype);
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer); INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, INT16 *extBuffer);
void G_AddMapToBuffer(INT16 map); void G_AddMapToBuffer(INT16 map);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -5282,7 +5282,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 encoremapcache = NEXTMAP_INVALID; static UINT16 encoremapcache = NEXTMAP_INVALID;
if (encoremapcache > nummapheaders) if (encoremapcache > nummapheaders)
{ {
encoremapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); encoremapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL);
} }
specialmap = encoremapcache; specialmap = encoremapcache;
break; break;
@ -5292,7 +5292,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 tamapcache = NEXTMAP_INVALID; static UINT16 tamapcache = NEXTMAP_INVALID;
if (tamapcache > nummapheaders) if (tamapcache > nummapheaders)
{ {
tamapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); tamapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL);
} }
specialmap = tamapcache; specialmap = tamapcache;
break; break;
@ -5302,7 +5302,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 btcmapcache = NEXTMAP_INVALID; static UINT16 btcmapcache = NEXTMAP_INVALID;
if (btcmapcache > nummapheaders) if (btcmapcache > nummapheaders)
{ {
btcmapcache = G_RandMap(G_TOLFlag(GT_BATTLE), -1, 2, 0, false, NULL); btcmapcache = G_RandMap(G_TOLFlag(GT_BATTLE), -1, true, false, NULL);
} }
specialmap = btcmapcache; specialmap = btcmapcache;
break; break;
@ -5312,7 +5312,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 sscmapcache = NEXTMAP_INVALID; static UINT16 sscmapcache = NEXTMAP_INVALID;
if (sscmapcache > nummapheaders) if (sscmapcache > nummapheaders)
{ {
sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), -1, 2, 0, false, NULL); sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), -1, true, false, NULL);
} }
specialmap = sscmapcache; specialmap = sscmapcache;
break; break;
@ -5322,7 +5322,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 spbmapcache = NEXTMAP_INVALID; static UINT16 spbmapcache = NEXTMAP_INVALID;
if (spbmapcache > nummapheaders) if (spbmapcache > nummapheaders)
{ {
spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); spbmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL);
} }
specialmap = spbmapcache; specialmap = spbmapcache;
break; break;
@ -5332,7 +5332,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 hardmapcache = NEXTMAP_INVALID; static UINT16 hardmapcache = NEXTMAP_INVALID;
if (hardmapcache > nummapheaders) if (hardmapcache > nummapheaders)
{ {
hardmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); hardmapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL);
} }
specialmap = hardmapcache; specialmap = hardmapcache;
break; break;
@ -5342,7 +5342,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 mastermapcache = NEXTMAP_INVALID; static UINT16 mastermapcache = NEXTMAP_INVALID;
if (mastermapcache > nummapheaders) if (mastermapcache > nummapheaders)
{ {
mastermapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, 2, 0, false, NULL); mastermapcache = G_RandMap(G_TOLFlag(GT_RACE), -1, true, false, NULL);
} }
specialmap = mastermapcache; specialmap = mastermapcache;
break; break;

View file

@ -76,7 +76,7 @@
#define BULB_FRAMES (4) #define BULB_FRAMES (4)
#define CATCHER_SPEED (8*FRACUNIT) #define CATCHER_SPEED (8*FRACUNIT)
#define CATCHER_Y_OFFSET (32*FRACUNIT) #define CATCHER_Y_OFFSET (48*FRACUNIT)
#define CATCHER_OFFSCREEN (-CATCHER_Y_OFFSET * 2) #define CATCHER_OFFSCREEN (-CATCHER_Y_OFFSET * 2)
#define SELECTION_WIDTH (72*FRACUNIT) #define SELECTION_WIDTH (72*FRACUNIT)