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 *p = buf;
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, G_SometimesGetDifferentEncore());
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;
WRITEUINT16(p, m);
}
@ -3202,7 +3210,7 @@ static void Command_RandomMap(void)
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);
}

View file

@ -410,6 +410,8 @@ struct mapheader_t
cupheader_t *cup; ///< Cached cup
size_t justPlayed; ///< Prevent this map from showing up in votes if it was recently picked.
// Titlecard information
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

View file

@ -2250,7 +2250,7 @@ void F_TitleScreenTicker(boolean run)
// prevent console spam if failed
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
{
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 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
{
INT32 xaxis;
@ -3726,188 +3709,170 @@ static INT32 TOLMaps(UINT8 pgametype)
* has those flags.
* \author Graue <graue@oceanbase.org>
*/
static INT16 *okmaps = NULL;
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer)
static INT16 *g_allowedMaps = NULL;
#ifdef PARANOIA
static INT32 g_randMapStack = 0;
#endif
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, boolean ignoreBuffers, boolean callAgainSoon, INT16 *extBuffer)
{
UINT32 numokmaps = 0;
INT16 ix, bufx;
UINT16 extbufsize = 0;
INT32 allowedMapsCount = 0;
INT32 extBufferCount = 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");
okmaps = Z_Malloc(nummapheaders * sizeof(INT16), PU_STATIC, NULL);
}
if (extbuffer != NULL)
{
bufx = 0;
while (extbuffer[bufx])
for (i = 0; extBuffer[i] != 0; i++)
{
extbufsize++;
bufx++;
extBufferCount++;
}
}
tryagain:
tryAgain:
// Find all the maps that are ok and and put them in an array.
for (ix = 0; ix < nummapheaders; ix++)
for (i = 0; i < nummapheaders; i++)
{
boolean isokmap = true;
if (!mapheaderinfo[ix] || mapheaderinfo[ix]->lumpnum == LUMPERROR)
if (mapheaderinfo[i] == NULL || mapheaderinfo[i]->lumpnum == LUMPERROR)
{
// Doesn't exist?
continue;
}
if (!(mapheaderinfo[ix]->typeoflevel & tolflags)
|| ix == pprevmap
|| M_MapLocked(ix+1)
|| (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU)) // this is bad
if (i == pprevmap)
{
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
&& mapheaderinfo[ix]->ghostCount == 0)
&& mapheaderinfo[i]->ghostCount == 0)
{
// Doesn't have any ghosts, so it's not suitable for title demos.
continue;
}
if (!ignorebuffer)
if ((mapheaderinfo[i]->menuflags & LF2_HIDEINMENU) == LF2_HIDEINMENU)
{
if (extbufsize > 0)
// Not intended to be accessed in multiplayer.
continue;
}
if (M_MapLocked(i + 1) == true)
{
// We haven't earned this one.
continue;
}
if (ignoreBuffers == false)
{
if (mapheaderinfo[i]->justPlayed > 0)
{
for (bufx = 0; bufx < extbufsize; bufx++)
// We just played this map, don't play it again.
continue;
}
if (extBufferCount > 0)
{
// An optional additional buffer,
// to avoid duplicates on the voting screen.
for (j = 0; j < extBufferCount; j++)
{
if (extbuffer[bufx] == -1) // Rest of buffer SHOULD be empty
if (extBuffer[j] < 0 || extBuffer[j] >= nummapheaders)
{
// Rest of buffer SHOULD be empty.
break;
}
if (ix == extbuffer[bufx])
if (i == extBuffer[j])
{
isokmap = false;
// Map is in this other buffer, don't duplicate.
break;
}
}
if (!isokmap)
if (j < extBufferCount)
{
// Didn't make it out of this buffer, so don't add this map.
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;
}
okmaps[numokmaps++] = ix;
// Got past the gauntlet, so we can allow this one.
g_allowedMaps[ allowedMapsCount++ ] = i;
}
if (numokmaps == 0) // If there's no matches... (Goodbye, incredibly silly function chains :V)
if (allowedMapsCount == 0)
{
if (!ignorebuffer)
// No maps are available.
if (ignoreBuffers == false)
{
if (randmaps.mapbuffer[VOTE_NUM_LEVELS] == -1) // Is the buffer basically empty?
{
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...
{
randmaps.mapbuffer[bufx] = -1;
}
//CONS_Printf("RANDMAP - emptying randmapbuffer\n");
goto tryagain;
// Try again with ignoring the buffer before giving up.
ignoreBuffers = true;
goto tryAgain;
}
//CONS_Printf("RANDMAP - defaulting to map01\n");
ix = 0; // Sorry, none match. You get MAP01.
if (ignorebuffer == 1)
{
//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
}
}
// Nothing else actually worked. Welp!
// You just get whatever was added first.
ret = 0;
}
else
{
//CONS_Printf("RANDMAP - %d maps available to grab\n", numokmaps);
ix = okmaps[M_RandomKey(numokmaps)];
ret = g_allowedMaps[ M_RandomKey(allowedMapsCount) ];
}
if (!callagainsoon)
if (callAgainSoon == false)
{
//CONS_Printf("(freeing okmaps)\n");
Z_Free(okmaps);
okmaps = NULL;
Z_Free(g_allowedMaps);
g_allowedMaps = 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)
{
INT16 bufx;
INT16 refreshnum = (TOLMaps(gametype)) - VOTE_NUM_LEVELS;
if (refreshnum < 0)
if (mapheaderinfo[map]->justPlayed == 0) // Started playing a new map.
{
refreshnum = 0;
}
if (nummapheaders != randmaps.lastnummapheaders)
{
G_ResetRandMapBuffer();
}
else
{
for (bufx = randmaps.lastnummapheaders - 1; bufx > 0; bufx--)
// Decrement every maps' justPlayed value.
INT32 i;
for (i = 0; i < nummapheaders; i++)
{
randmaps.mapbuffer[bufx] = randmaps.mapbuffer[bufx-1];
if (mapheaderinfo[i]->justPlayed > 0)
{
mapheaderinfo[i]->justPlayed--;
}
}
}
randmaps.mapbuffer[0] = map;
// 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");
}
// Set our map's justPlayed value.
mapheaderinfo[map]->justPlayed = TOLMaps(gametype) - VOTE_NUM_LEVELS;
}
//
@ -4234,7 +4199,7 @@ static void G_GetNextMap(void)
}
/* FALLTHRU */
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;
default:
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_ResetRandMapBuffer();
// this leave the actual game if needed
SV_StartSinglePlayerServer(gametype, false);

View file

@ -255,7 +255,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics);
UINT32 G_TOLFlag(INT32 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);
#ifdef __cplusplus

View file

@ -5282,7 +5282,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 encoremapcache = NEXTMAP_INVALID;
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;
break;
@ -5292,7 +5292,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 tamapcache = NEXTMAP_INVALID;
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;
break;
@ -5302,7 +5302,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 btcmapcache = NEXTMAP_INVALID;
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;
break;
@ -5312,7 +5312,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 sscmapcache = NEXTMAP_INVALID;
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;
break;
@ -5322,7 +5322,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 spbmapcache = NEXTMAP_INVALID;
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;
break;
@ -5332,7 +5332,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 hardmapcache = NEXTMAP_INVALID;
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;
break;
@ -5342,7 +5342,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
static UINT16 mastermapcache = NEXTMAP_INVALID;
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;
break;

View file

@ -76,7 +76,7 @@
#define BULB_FRAMES (4)
#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 SELECTION_WIDTH (72*FRACUNIT)