Merge branch 'map-access-flingerdinger' into 'master'

Stronger Course progression restriction

Closes #832, #859, and #839

See merge request KartKrew/Kart!1795
This commit is contained in:
Oni 2024-01-09 08:11:12 +00:00
commit df5c866573
13 changed files with 257 additions and 119 deletions

View file

@ -1372,13 +1372,6 @@ void readlevelheader(MYFILE *f, char * name)
else
mapheaderinfo[num]->menuflags &= ~LF2_HIDEINMENU;
}
else if (fastcmp(word, "HIDEINSTATS"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num]->menuflags |= LF2_HIDEINSTATS;
else
mapheaderinfo[num]->menuflags &= ~LF2_HIDEINSTATS;
}
else if (fastcmp(word, "NOTIMEATTACK") || fastcmp(word, "NORECORDATTACK"))
{ // RECORDATTACK is an accepted alias
if (i || word2[0] == 'T' || word2[0] == 'Y')
@ -1393,6 +1386,13 @@ void readlevelheader(MYFILE *f, char * name)
else
mapheaderinfo[num]->menuflags &= ~LF2_FINISHNEEDED;
}
else if (fastcmp(word, "NOVISITNEEDED"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num]->menuflags |= LF2_NOVISITNEEDED;
else
mapheaderinfo[num]->menuflags &= ~LF2_NOVISITNEEDED;
}
else if (fastcmp(word, "GRAVITY"))
mapheaderinfo[num]->gravity = FLOAT_TO_FIXED(atof(word2));
else if (fastcmp(word, "DESTROYOBJECTSFORCHALLENGES"))

View file

@ -6890,8 +6890,8 @@ struct int_const_s const INT_CONST[] = {
{"LF_SUBTRACTNUM",LF_SUBTRACTNUM},
// And map flags
{"LF2_HIDEINMENU",LF2_HIDEINMENU},
{"LF2_HIDEINSTATS",LF2_HIDEINSTATS},
{"LF2_NOTIMEATTACK",LF2_NOTIMEATTACK},
{"LF2_NOVISITNEEDED",LF2_NOVISITNEEDED},
{"LF2_FINISHNEEDED",LF2_FINISHNEEDED},
// Emeralds

View file

@ -151,8 +151,6 @@ struct skinreference_t
#define MV_SPBATTACK (1<<3)
#define MV_MYSTICMELODY (1<<4)
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK|MV_MYSTICMELODY)
#define MV_FINISHNEEDED (1<<7)
#define MV_PERSISTUNLOADED (MV_SPBATTACK|MV_FINISHNEEDED)
struct recorddata_t
{
@ -573,8 +571,8 @@ struct mapheader_t
#define LF_SUBTRACTNUM (1<<3) ///< Use subtractive position number (for bright levels)
#define LF2_HIDEINMENU (1<<0) ///< Hide in the multiplayer menu
#define LF2_HIDEINSTATS (1<<1) ///< Hide in the statistics screen
#define LF2_NOTIMEATTACK (1<<2) ///< Hide this map in Time Attack modes
#define LF2_NOTIMEATTACK (1<<1) ///< Hide this map in Time Attack modes
#define LF2_NOVISITNEEDED (1<<2) ///< Map does not require visitation to be selectable
#define LF2_FINISHNEEDED (1<<3) ///< Not available in Time Attack modes until you beat the level
extern mapheader_t** mapheaderinfo;

View file

@ -3451,10 +3451,32 @@ static INT32 TOLMaps(UINT8 pgametype)
continue;
}
if (M_MapLocked(i + 1))
// Only care about restrictions if the host is a listen server.
if (!dedicated)
{
// Don't include locked
continue;
if (!(mapheaderinfo[i]->menuflags & LF2_NOVISITNEEDED)
&& !(mapheaderinfo[i]->records.mapvisited & MV_VISITED)
&& !(
mapheaderinfo[i]->cup
&& mapheaderinfo[i]->cup->cachedlevels[0] == i
))
{
// Not visited OR head of cup
continue;
}
if ((mapheaderinfo[i]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[i]->records.mapvisited & MV_BEATEN))
{
// Not completed
continue;
}
if (M_MapLocked(i + 1) == true)
{
// We haven't earned this one.
continue;
}
}
num++;
@ -3536,10 +3558,32 @@ tryAgain:
continue;
}
if (M_MapLocked(i + 1) == true)
// Only care about restrictions if the host is a listen server.
if (!dedicated)
{
// We haven't earned this one.
continue;
if (!(mapheaderinfo[i]->menuflags & LF2_NOVISITNEEDED)
&& !(mapheaderinfo[i]->records.mapvisited & MV_VISITED)
&& !(
mapheaderinfo[i]->cup
&& mapheaderinfo[i]->cup->cachedlevels[0] == i
))
{
// Not visited OR head of cup
continue;
}
if ((mapheaderinfo[i]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[i]->records.mapvisited & MV_BEATEN))
{
// Not completed
continue;
}
if (M_MapLocked(i + 1) == true)
{
// We haven't earned this one.
continue;
}
}
if (ignoreBuffers == false)
@ -3974,7 +4018,7 @@ void G_GetNextMap(void)
continue;
}
for (i = 0; i < cup->numlevels; i++)
for (i = 0; i < CUPCACHE_PODIUM; i++)
{
cm = cup->cachedlevels[i];
@ -3982,9 +4026,35 @@ void G_GetNextMap(void)
if (cm >= nummapheaders
|| !mapheaderinfo[cm]
|| mapheaderinfo[cm]->lumpnum == LUMPERROR
|| !(mapheaderinfo[cm]->typeoflevel & tolflag)
|| (!marathonmode && M_MapLocked(cm+1)))
|| !(mapheaderinfo[cm]->typeoflevel & tolflag))
{
continue;
}
// Only care about restrictions if the host is a listen server.
if (!dedicated && !marathonmode)
{
if (!(mapheaderinfo[cm]->menuflags & LF2_NOVISITNEEDED)
&& !(mapheaderinfo[cm]->records.mapvisited & MV_VISITED)
&& i != 0)
{
// Not visited OR head of cup
continue;
}
if ((mapheaderinfo[cm]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[cm]->records.mapvisited & MV_BEATEN))
{
// Not completed
continue;
}
if (M_MapLocked(cm + 1) == true)
{
// We haven't earned this one.
continue;
}
}
// If the map is in multiple cups, only consider the first one valid.
if (mapheaderinfo[cm]->cup != cup)
@ -4029,24 +4099,50 @@ void G_GetNextMap(void)
else
{
cm = prevmap;
if (++cm >= nummapheaders)
cm = 0;
while (cm != prevmap)
do
{
if (++cm >= nummapheaders)
cm = 0;
if (!mapheaderinfo[cm]
|| mapheaderinfo[cm]->lumpnum == LUMPERROR
|| !(mapheaderinfo[cm]->typeoflevel & tolflag)
|| (mapheaderinfo[cm]->menuflags & LF2_HIDEINMENU)
|| M_MapLocked(cm+1))
|| (mapheaderinfo[cm]->menuflags & LF2_HIDEINMENU))
{
if (++cm >= nummapheaders)
cm = 0;
continue;
}
// Only care about restrictions if the host is a listen server.
if (!dedicated && !marathonmode)
{
if (!(mapheaderinfo[cm]->menuflags & LF2_NOVISITNEEDED)
&& !(mapheaderinfo[cm]->records.mapvisited & MV_VISITED)
&& !(
mapheaderinfo[cm]->cup
&& mapheaderinfo[cm]->cup->cachedlevels[0] == cm
))
{
// Not visited OR head of cup
continue;
}
if ((mapheaderinfo[cm]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[cm]->records.mapvisited & MV_BEATEN))
{
// Not completed
continue;
}
if (M_MapLocked(cm + 1) == true)
{
// We haven't earned this one.
continue;
}
}
break;
}
} while (cm != prevmap);
nextmap = cm;
}
@ -4295,26 +4391,27 @@ static void G_DoCompleted(void)
// If the current gametype has no intermission screen set, then don't start it.
Y_DetermineIntermissionType();
if (intertype == int_none)
if (intertype != int_none)
{
G_UpdateVisited();
if (grandprixinfo.gp == true)
{
K_UpdateGPRank(&grandprixinfo.rank);
}
G_AfterIntermission();
}
else
{
G_SetGamestate(GS_INTERMISSION);
Y_StartIntermission();
G_UpdateVisited();
}
else if (grandprixinfo.gp == true)
{
K_UpdateGPRank(&grandprixinfo.rank);
}
G_UpdateVisited();
// This isn't in the above blocks because many
// mechanisms can queue up a gamedata save.
if (gamedata->deferredsave)
G_SaveGameData();
// Seperate from the above, as Y_StartIntermission can no-sell.
if (intertype == int_none)
{
G_AfterIntermission();
}
}
// See also F_EndCutscene, the only other place which handles intra-map/ending transitions
@ -4972,8 +5069,7 @@ void G_LoadGameData(void)
M_Memcpy(&mapheaderinfo[mapnum]->records, &dummyrecord, sizeof(recorddata_t));
}
else if (
((dummyrecord.mapvisited & MV_PERSISTUNLOADED) != 0
&& (dummyrecord.mapvisited & MV_BEATEN) != 0)
(dummyrecord.mapvisited & MV_BEATEN)
|| dummyrecord.time != 0
|| dummyrecord.lap != 0
)
@ -5575,11 +5671,6 @@ void G_SaveGameData(void)
UINT8 mapvisitedtemp = (mapheaderinfo[i]->records.mapvisited & MV_MAX);
if ((mapheaderinfo[i]->menuflags & (LF2_FINISHNEEDED|LF2_HIDEINMENU)))
{
mapvisitedtemp |= MV_FINISHNEEDED;
}
WRITEUINT8(save.p, mapvisitedtemp);
WRITEUINT32(save.p, mapheaderinfo[i]->records.time);

View file

@ -97,6 +97,7 @@ static char hu_tick;
patch_t *missingpat;
patch_t *blanklvl, *nolvl;
patch_t *unvisitedlvl[4];
// song credits
static patch_t *songcreditbg;
@ -196,6 +197,11 @@ void HU_LoadGraphics(void)
HU_UpdatePatch(&blanklvl, "BLANKLVL");
HU_UpdatePatch(&nolvl, "M_NOLVL");
for (i = 0; i < 4; i++)
{
HU_UpdatePatch(&unvisitedlvl[i], "PREVST0%d", i+1);
}
HU_UpdatePatch(&songcreditbg, "K_SONGCR");
// cache ping gfx:

View file

@ -205,6 +205,17 @@ void M_PickMenuBGMap(void)
continue;
}
if (!(mapheaderinfo[i]->menuflags & LF2_NOVISITNEEDED)
&& !(mapheaderinfo[i]->records.mapvisited & MV_VISITED)
&& !(
mapheaderinfo[i]->cup
&& mapheaderinfo[i]->cup->cachedlevels[0] == i
))
{
// Not visited OR head of cup
continue;
}
if (M_MapLocked(i + 1) == true)
{
// We haven't earned this one.
@ -2676,24 +2687,28 @@ void M_DrawRaceDifficulty(void)
// LEVEL SELECT
static void M_DrawCupPreview(INT16 y, levelsearch_t *levelsearch)
static void M_DrawCupPreview(INT16 y, levelsearch_t *baselevelsearch)
{
levelsearch_t locklesslevelsearch = *baselevelsearch; // full copy
locklesslevelsearch.checklocked = false;
UINT8 i = 0;
INT16 maxlevels = M_CountLevelsToShowInList(levelsearch);
INT16 maxlevels = M_CountLevelsToShowInList(&locklesslevelsearch);
const fixed_t step = (82 * FRACUNIT);
fixed_t previewanimwork = (cupgrid.previewanim * FRACUNIT) + rendertimefrac_unpaused;
fixed_t x = -(previewanimwork % step);
INT16 add;
INT16 map, start = M_GetFirstLevelInList(&i, levelsearch);
INT16 map, start = M_GetFirstLevelInList(&i, &locklesslevelsearch);
UINT8 starti = i;
if (levelsearch->cup && maxlevels > 0)
patch_t *staticpat = unvisitedlvl[cupgrid.previewanim % 4];
if (baselevelsearch->cup && maxlevels > 0)
{
add = (previewanimwork / step) % maxlevels;
INT16 add = (previewanimwork / step) % maxlevels;
map = start;
while (add > 0)
{
map = M_GetNextLevelInList(map, &i, levelsearch);
map = M_GetNextLevelInList(map, &i, &locklesslevelsearch);
if (map >= nummapheaders)
{
@ -2710,24 +2725,35 @@ static void M_DrawCupPreview(INT16 y, levelsearch_t *levelsearch)
i = starti;
}
K_DrawMapThumbnail(
x + FRACUNIT, (y+2)<<FRACBITS,
80<<FRACBITS,
0,
map,
NULL);
if (M_CanShowLevelInList(map, baselevelsearch))
{
K_DrawMapThumbnail(
x + FRACUNIT, (y+2)<<FRACBITS,
80<<FRACBITS,
0,
map,
NULL);
}
else
{
V_DrawFixedPatch(
x + FRACUNIT, (y+2) * FRACUNIT,
FRACUNIT,
0,
staticpat,
NULL);
}
x += step;
map = M_GetNextLevelInList(map, &i, levelsearch);
map = M_GetNextLevelInList(map, &i, &locklesslevelsearch);
}
}
else
{
patch_t *st = W_CachePatchName(va("PREVST0%d", (cupgrid.previewanim % 4) + 1), PU_CACHE);
while (x < BASEVIDWIDTH * FRACUNIT)
{
V_DrawFixedPatch(x + FRACUNIT, (y+2) * FRACUNIT, FRACUNIT, 0, st, NULL);
V_DrawFixedPatch(x + FRACUNIT, (y+2) * FRACUNIT, FRACUNIT, 0, staticpat, NULL);
x += step;
}
}
@ -3118,7 +3144,13 @@ void M_DrawCupSelect(void)
&& templevelsearch.cup != NULL
&& templevelsearch.cup == cupsavedata.cup)
{
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP2", PU_CACHE));
V_DrawScaledPatch(
14 + (cupgrid.x*42) + 32,
20 + (cupgrid.y*44) + 32
+ ((cupgrid.cache_secondrowlocked == true) ? 28 : 0),
0,
W_CachePatchName("CUPBKUP2", PU_CACHE)
);
}
INT16 ty = M_EaseWithTransition(Easing_Linear, 5 * 24);
@ -6374,7 +6406,7 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
templevelsearch.cupmode = true;
templevelsearch.timeattack = false;
templevelsearch.tutorial = false;
templevelsearch.checklocked = false;
templevelsearch.checklocked = true;
M_DrawCupPreview(146, &templevelsearch);
@ -7177,7 +7209,7 @@ static void M_DrawStatsMaps(void)
for (i = 0; i < nummapheaders; i++)
{
// Check for no visibility
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU)))
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINMENU)))
continue;
// Has to be accessible via time attack

View file

@ -1094,7 +1094,7 @@ static void M_PrecacheLevelLocks(void)
{
if (!mapheaderinfo[mapcheck] || mapheaderinfo[mapcheck]->cup != NULL)
continue;
if (mapheaderinfo[mapcheck]->menuflags & (LF2_HIDEINSTATS|LF2_HIDEINMENU))
if (mapheaderinfo[mapcheck]->menuflags & LF2_HIDEINMENU)
continue;
if (((mapheaderinfo[mapcheck]->typeoflevel & TOL_TUTORIAL) == TOL_TUTORIAL)
!= ((mapheaderinfo[map]->typeoflevel & TOL_TUTORIAL) == TOL_TUTORIAL))
@ -1468,6 +1468,11 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
case UC_UNLOCKPERCENT:
{
// Don't let netgame sessions intefere
// (or have this give a performance hit)
if (Playing())
return false;
UINT16 i, unlocked = cn->extrainfo2, total = 0;
// Special case for maps
@ -1475,7 +1480,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
{
for (i = 0; i < basenummapheaders; i++)
{
if (!mapheaderinfo[i] || mapheaderinfo[i]->menuflags & (LF2_HIDEINSTATS|LF2_HIDEINMENU))
if (!mapheaderinfo[i] || mapheaderinfo[i]->menuflags & (LF2_HIDEINMENU))
continue;
total++;
@ -1957,7 +1962,7 @@ static char *M_BuildConditionTitle(UINT16 map)
{
char *title, *ref;
if (((mapheaderinfo[map]->menuflags & LF2_FINISHNEEDED)
if ((!(mapheaderinfo[map]->menuflags & LF2_NOVISITNEEDED)
// the following is intentionally not MV_BEATEN, just in case the title is for "Finish a round on X"
&& !(mapheaderinfo[map]->records.mapvisited & MV_VISITED))
|| M_MapLocked(map+1))

View file

@ -21,13 +21,22 @@ static boolean M_StatisticsAddMap(UINT16 map, cupheader_t *cup, boolean *headere
return false;
// Check for no visibility
if (mapheaderinfo[map]->menuflags & (LF2_HIDEINSTATS|LF2_HIDEINMENU))
if (mapheaderinfo[map]->menuflags & LF2_HIDEINMENU)
return false;
// Check for visitation
// (M_CanShowLevelInList also checks being the first map in a cup,
// but we don't need to do this here because it'd just muddy stats!)
if (!(mapheaderinfo[map]->menuflags & LF2_NOVISITNEEDED)
&& !(mapheaderinfo[map]->records.mapvisited & MV_VISITED))
return false;
#if 0
// Check for completion
if ((mapheaderinfo[map]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[map]->records.mapvisited & MV_BEATEN))
return false;
#endif
// Check for unlock
if (M_MapLocked(map+1))
@ -80,11 +89,7 @@ static void M_StatisticsMaps(void)
headerexists = false;
for (i = 0; i < nummapheaders; i++)
{
if (M_StatisticsAddMap(i, NULL, &headerexists, true))
{
if (!(mapheaderinfo[i]->records.mapvisited & MV_BEATEN))
break;
}
M_StatisticsAddMap(i, NULL, &headerexists, true);
}
if ((i = statisticsmenu.numextramedals) != 0)

View file

@ -77,11 +77,11 @@ boolean M_CanShowLevelInList(INT16 mapnum, levelsearch_t *levelsearch)
if (levelsearch->timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK))
return false;
cupheader_t *cup = (levelsearch->cup == &dummy_lostandfound) ? NULL : levelsearch->cup;
// Don't permit cup when no cup requested (also no dupes in time attack)
if (levelsearch->cupmode)
{
cupheader_t *cup = (levelsearch->cup == &dummy_lostandfound) ? NULL : levelsearch->cup;
if ((!cup || levelsearch->timeattack)
&& mapheaderinfo[mapnum]->cup != cup)
return false;
@ -90,6 +90,12 @@ boolean M_CanShowLevelInList(INT16 mapnum, levelsearch_t *levelsearch)
// Finally, the most complex check: does the map have lock conditions?
if (levelsearch->checklocked)
{
// Check for visitation
if (!(mapheaderinfo[mapnum]->menuflags & LF2_NOVISITNEEDED)
&& !(mapheaderinfo[mapnum]->records.mapvisited & MV_VISITED)
&& !(cup && cup->cachedlevels[0] == mapnum))
return false;
// Check for completion
if ((mapheaderinfo[mapnum]->menuflags & LF2_FINISHNEEDED)
&& !(mapheaderinfo[mapnum]->records.mapvisited & MV_BEATEN))
@ -128,22 +134,9 @@ UINT16 M_CountLevelsToShowInList(levelsearch_t *levelsearch)
for (i = 0; i < nummapheaders; i++)
{
if (M_CanShowLevelInList(i, levelsearch))
{
count++;
// Tutorial will only show what you've made your way to
if (!levelsearch->checklocked)
continue;
if (!levelsearch->tutorial)
continue;
if (i >= basenummapheaders)
continue;
if (mapheaderinfo[i]->records.mapvisited & MV_BEATEN)
continue;
break;
}
if (!M_CanShowLevelInList(i, levelsearch))
continue;
count++;
}
return count;
@ -206,13 +199,6 @@ UINT16 M_GetNextLevelInList(UINT16 mapnum, UINT8 *i, levelsearch_t *levelsearch)
}
else
{
// Tutorial will only show what you've made your way to
if (levelsearch->checklocked
&& levelsearch->tutorial
&& mapnum < basenummapheaders
&& !(mapheaderinfo[mapnum]->records.mapvisited & MV_BEATEN))
return NEXTMAP_INVALID;
mapnum++;
while (!M_CanShowLevelInList(mapnum, levelsearch) && mapnum < nummapheaders)
mapnum++;

View file

@ -336,7 +336,14 @@ void M_HandlePauseMenuGametype(INT32 choice)
M_ClearMenus(true);
if (server || IsPlayerAdmin(consoleplayer))
{
D_SetupVote(menugametype);
if (cv_advancemap.value == 3) // Voting screen.
{
D_SetupVote(menugametype);
}
else // ideally for "random" only, but no sane fallback for "same" and "next"
{
COM_ImmedExecute(va("randommap -gt %s", gametypes[menugametype]->name));
}
}
return;
}

View file

@ -900,6 +900,7 @@ struct patch_t
extern patch_t *missingpat;
extern patch_t *blanklvl, *nolvl;
extern patch_t *unvisitedlvl[4];
#if defined(_MSC_VER)
#pragma pack(1)

View file

@ -1393,11 +1393,13 @@ static boolean S_SoundTestDefLocked(musicdef_t *def)
mapheader_t *header = mapheaderinfo[def->sequence.map];
// Is the level tied to SP progression?
if ((
(header->menuflags & (LF2_FINISHNEEDED|LF2_HIDEINMENU))
|| (def->sequence.altref == ALTREF_REQUIRESBEATEN) // Associated music only when completed
)
// Visitation required?
if (!(header->menuflags & LF2_NOVISITNEEDED)
&& !(header->records.mapvisited & MV_VISITED))
return true;
// Associated music only when completed
if ((def->sequence.altref == ALTREF_REQUIRESBEATEN)
&& !(header->records.mapvisited & MV_BEATEN))
return true;

View file

@ -1982,10 +1982,7 @@ void Y_StartIntermission(void)
// determine the tic everybody's scores/PWR starts getting sorted
sorttic = -1;
if (!timer)
{
// Prevent a weird bug
timer = 1;
}
;
else if (
( // Match Race or Time Attack
netgame == false
@ -2033,11 +2030,6 @@ void Y_StartIntermission(void)
if (prevmap >= nummapheaders || !mapheaderinfo[prevmap])
I_Error("Y_StartIntermission: Internal map ID %d not found (nummapheaders = %d)", prevmap, nummapheaders);
if (timer > 1 && musiccountdown == 0)
Music_Play("intermission");
S_ShowMusicCredit(); // Always call
switch (intertype)
{
case int_score:
@ -2058,9 +2050,6 @@ void Y_StartIntermission(void)
break;
}
LUA_HUD_DestroyDrawList(luahuddrawlist_intermission);
luahuddrawlist_intermission = LUA_HUD_CreateDrawList();
if (powertype != PWRLV_DISABLED)
{
for (i = 0; i < MAXPLAYERS; i++)
@ -2078,6 +2067,22 @@ void Y_StartIntermission(void)
SV_BumpMatchStats();
}
if (!timer)
{
Y_EndIntermission();
return;
}
G_SetGamestate(GS_INTERMISSION);
if (musiccountdown == 0)
Music_Play("intermission");
S_ShowMusicCredit(); // Always call
LUA_HUD_DestroyDrawList(luahuddrawlist_intermission);
luahuddrawlist_intermission = LUA_HUD_CreateDrawList();
if (roundqueue.size > 0 && roundqueue.position == roundqueue.size)
{
Automate_Run(AEV_QUEUEEND);