Round Queue UI on Level Select

- Only works in Match Race and Online level selects
- Shows in-progress state on Pause and Cup Grid, but no direct influence available on those screens
- Z to queue current highlighted map
    - Pending until you press A, then sent to server
    - When done online, tries to send one at a time to avoid overloading connection
- C to clear
    - Removes one from pending first
    - If you're out of pending maps, prompts whether you want to clear server's queue
This commit is contained in:
toaster 2025-05-31 22:25:52 +01:00
parent 5bfbfccdae
commit 830cfe76da
15 changed files with 487 additions and 90 deletions

View file

@ -1213,6 +1213,7 @@ void D_ClearState(void)
// Reset GP and roundqueue
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
memset(&roundqueue, 0, sizeof(struct roundqueue));
memset(&menuqueue, 0, sizeof(struct menuqueue));
// empty some other semi-important state
maptol = 0;

View file

@ -2984,7 +2984,7 @@ static void Command_RestartLevel(void)
D_MapChange(gamemap, g_lastgametype, newencore, false, 0, false, false);
}
static void Handle_MapQueueSend(UINT16 newmapnum, UINT16 newgametype, boolean newencoremode)
void Handle_MapQueueSend(UINT16 newmapnum, UINT16 newgametype, boolean newencoremode)
{
UINT8 flags = 0;

View file

@ -206,6 +206,7 @@ size_t WeaponPref_Parse(const UINT8 *p, INT32 playernum);
void D_SendPlayerConfig(UINT8 n);
void Command_ExitGame_f(void);
void Command_Retry_f(void);
void Handle_MapQueueSend(UINT16 newmapnum, UINT16 newgametype, boolean newencoremode);
boolean G_GamestateUsesExitLevel(void);
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore
void D_MapChange(UINT16 pmapnum, INT32 pgametype, boolean pencoremode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pforcespecialstage);

View file

@ -4106,6 +4106,7 @@ doremove:
// Next map apparatus
struct roundqueue roundqueue;
struct menuqueue menuqueue;
void G_MapSlipIntoRoundQueue(UINT8 position, UINT16 map, UINT8 setgametype, boolean setencore, boolean rankrestricted)
{

View file

@ -75,6 +75,15 @@ extern struct roundqueue
roundentry_t entries[ROUNDQUEUE_MAX]; // Entries in the round queue
} roundqueue;
extern struct menuqueue
{
// Degenerate version of roundqueue exclusively for menu use.
UINT8 size;
UINT8 sending;
UINT8 anchor;
roundentry_t entries[ROUNDQUEUE_MAX];
} menuqueue;
void G_MapSlipIntoRoundQueue(UINT8 position, UINT16 map, UINT8 setgametype, boolean setencore, boolean rankrestricted);
void G_MapIntoRoundQueue(UINT16 map, UINT8 setgametype, boolean setencore, boolean rankrestricted);
void G_GPCupIntoRoundQueue(cupheader_t *cup, UINT8 setgametype, boolean setencore);

View file

@ -1536,6 +1536,46 @@ void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, p
);
}
void K_DrawMapAsFace(INT32 x, INT32 y, UINT32 flags, UINT16 map, const UINT8 *colormap)
{
const fixed_t iconHeight = (14 << FRACBITS);
const fixed_t iconWidth = (iconHeight * 320) / 200;
INT32 unit = 1;
fixed_t mul = FRACUNIT;
if (flags & V_NOSCALESTART)
{
unit = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
mul = 1;
}
V_DrawFill(
x,
y,
16 * unit,
16 * unit,
(flags & ~V_FLIP)
);
V_SetClipRect(
(x + unit) * mul,
(y + unit) * mul,
(14 * unit) * mul,
(14 * unit) * mul,
(flags & ~V_FLIP)
);
K_DrawMapThumbnail(
((x + unit) * FRACUNIT) - (iconWidth - iconHeight)/2,
((y + unit) * FRACUNIT),
iconWidth,
flags,
map,
colormap
);
V_ClearClipRect();
}
// see also K_DrawNameTagItemSpy
static void K_drawKartItem(void)
{

View file

@ -60,6 +60,7 @@ void K_drawKart4PTimestamp(void);
void K_drawEmeraldWin(boolean overlay);
void K_DrawMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT16 map, const UINT8 *colormap);
void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, patch_t *patch, const UINT8 *colormap);
void K_DrawMapAsFace(INT32 x, INT32 y, UINT32 flags, UINT16 map, const UINT8 *colormap);
void K_drawTargetHUD(const vector3_t *origin, player_t *player);
void K_drawButton(fixed_t x, fixed_t y, INT32 flags, patch_t *button[2], boolean pressed);
void K_drawButtonAnim(INT32 x, INT32 y, INT32 flags, patch_t *button[2], tic_t animtic);

View file

@ -923,6 +923,7 @@ typedef struct levellist_s {
UINT8 guessgt;
levelsearch_t levelsearch;
boolean netgame; // Start the game in an actual server
boolean canqueue;
menu_t *backMenu;
} levellist_t;
@ -944,6 +945,7 @@ void M_CupSelectTick(void);
void M_LevelSelectHandler(INT32 choice);
void M_LevelSelectTick(void);
INT16 M_LevelFromScrolledList(INT16 add);
void M_MenuToLevelPreamble(UINT8 ssplayers, boolean nowipe);
void M_LevelSelected(INT16 add, boolean menuupdate);
boolean M_LevelSelectCupSwitch(boolean next, boolean skipones);

View file

@ -755,33 +755,40 @@ static void M_DrawMenuTyping(void)
}
// Largely replaced by boxed drawing mode in K_DrawGameControl and rich text
/*
static void M_DrawMediocreKeyboardKey(const char *text, INT32 *workx, INT32 worky, boolean push, boolean rightaligned)
static void M_DrawPauseRoundQueue(INT16 offset, boolean canqueue)
{
INT32 buttonwidth = V_StringWidth(text, 0) + 2;
y_data_t standings;
memset(&standings, 0, sizeof (standings));
if (rightaligned)
if (gamestate == GS_MENU)
{
(*workx) -= buttonwidth;
}
if (push)
{
worky += 2;
standings.mainplayer = MAXPLAYERS;
}
else
{
V_DrawFill((*workx)-1, worky+10, buttonwidth, 2, 24);
standings.mainplayer = (demo.playback ? displayplayers[0] : consoleplayer);
}
V_DrawFill((*workx)-1, worky, buttonwidth, 10, 16);
V_DrawString(
(*workx), worky + 1,
0, text
);
// See also G_GetNextMap, Y_CalculateMatchData
if (
canqueue == false
&& grandprixinfo.gp == true
&& netgame == false // TODO netgame Special Mode support
&& grandprixinfo.gamespeed >= KARTSPEED_NORMAL
&& roundqueue.size > 1
&& roundqueue.entries[roundqueue.size - 1].rankrestricted == true
&& (
gamedata->everseenspecial == true
|| roundqueue.position == roundqueue.size
)
)
{
// Additional cases in which it should always be shown.
standings.showrank = true;
}
Y_RoundQueueDrawer(&standings, offset, false, false, canqueue);
}
*/
// Draw the message popup submenu
void M_DrawMenuMessage(void)
@ -991,6 +998,16 @@ void M_Drawer(void)
// Draw message overlay when needed
M_DrawMenuMessage();
if (
(
currentMenu == &PLAY_LevelSelectDef
|| currentMenu == &PLAY_CupSelectDef
) && levellist.canqueue
)
{
M_DrawPauseRoundQueue(0, true);
}
}
if (menuwipe)
@ -6288,30 +6305,11 @@ void M_DrawPause(void)
V_DrawCenteredLSTitleLowString(220 + offset*2, 103, mainflags, word2);
}
const boolean rulescheck = (K_CanChangeRules(false) && (server || IsPlayerAdmin(consoleplayer)));
boolean drawqueue = (rulescheck && (menuqueue.size > 0));
if (gamestate != GS_INTERMISSION && roundqueue.size > 0)
{
y_data_t standings;
memset(&standings, 0, sizeof (standings));
standings.mainplayer = (demo.playback ? displayplayers[0] : consoleplayer);
// See also G_GetNextMap, Y_CalculateMatchData
if (
grandprixinfo.gp == true
&& netgame == false // TODO netgame Special Mode support
&& grandprixinfo.gamespeed >= KARTSPEED_NORMAL
&& roundqueue.size > 1
&& roundqueue.entries[roundqueue.size - 1].rankrestricted == true
&& (
gamedata->everseenspecial == true
|| roundqueue.position == roundqueue.size
)
)
{
// Additional cases in which it should always be shown.
standings.showrank = true;
}
if (roundqueue.position > 0 && roundqueue.position <= roundqueue.size)
{
patch_t *smallroundpatch = ST_getRoundPicture(true);
@ -6328,7 +6326,7 @@ void M_DrawPause(void)
V_DrawCenteredMenuString(24, 167 + offset/2, V_YELLOWMAP, M_GetGameplayMode());
Y_RoundQueueDrawer(&standings, offset/2, false, false);
drawqueue = true;
}
else if (gametype == GT_TUTORIAL)
{
@ -6347,6 +6345,11 @@ void M_DrawPause(void)
{
V_DrawMenuString(4, 188 + offset/2, V_YELLOWMAP, M_GetGameplayMode());
}
if (drawqueue)
{
M_DrawPauseRoundQueue(offset/2, rulescheck);
}
}
void M_DrawKickHandler(void)

View file

@ -700,35 +700,13 @@ static void Y_DrawVoteThumbnail(fixed_t center_x, fixed_t center_y, fixed_t widt
}
else if (vote.stage_striking == false) // Angry map
{
const fixed_t iconHeight = (14 << FRACBITS);
const fixed_t iconWidth = (iconHeight * 320) / 200;
V_DrawFill(
K_DrawMapAsFace(
fx + fw - whiteSq + dupx,
fy + fh - whiteSq + dupy,
whiteSq,
whiteSq,
0|flags|V_NOSCALESTART
);
V_SetClipRect(
fx + fw - whiteSq + (2 * dupx),
fy + fh - whiteSq + (2 * dupy),
whiteSq - (2 * dupx),
whiteSq - (2 * dupy),
flags|V_NOSCALESTART
);
K_DrawMapThumbnail(
((fx + fw - whiteSq + (2 * dupx)) * FRACUNIT) - (iconWidth - iconHeight),
(fy + fh - whiteSq + (2 * dupy)) * FRACUNIT,
iconWidth,
flags | V_NOSCALESTART | ((encore == true) ? V_FLIP : 0),
g_voteLevels[v][0],
NULL
);
V_ClearClipRect();
}
}
}

View file

@ -1272,6 +1272,7 @@ void M_GonerTutorial(INT32 choice)
// Please also see M_LevelSelectInit as called in extras-1.c
levellist.netgame = false;
levellist.canqueue = false;
levellist.levelsearch.checklocked = true;
levellist.levelsearch.grandprix = false;
levellist.levelsearch.timeattack = false;

View file

@ -172,6 +172,7 @@ void M_MPSetupNetgameMapSelect(INT32 choice)
// Yep, we'll be starting a netgame.
levellist.netgame = true;
levellist.canqueue = true;
// Make sure we reset those
levellist.levelsearch.timeattack = false;
levellist.levelsearch.checklocked = true;

View file

@ -21,6 +21,7 @@
#include "../../v_video.h"
#include "../../g_game.h" // G_GetBackupCupData
#include "../../p_saveg.h" // cupsavedata
#include "../../d_netcmd.h" // Handle_MapQueueSend
cupheader_t dummy_lostandfound;
@ -657,6 +658,7 @@ void M_LevelSelectInit(INT32 choice)
case 0:
levellist.levelsearch.grandprix = false;
levellist.levelsearch.timeattack = false;
levellist.canqueue = true;
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string);
CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto");
@ -666,10 +668,12 @@ void M_LevelSelectInit(INT32 choice)
case 1:
levellist.levelsearch.grandprix = false;
levellist.levelsearch.timeattack = true;
levellist.canqueue = false;
break;
case 2:
levellist.levelsearch.grandprix = true;
levellist.levelsearch.timeattack = false;
levellist.canqueue = false;
break;
default:
CONS_Alert(CONS_WARNING, "Bad level select init\n");
@ -732,7 +736,7 @@ void M_MenuToLevelPreamble(UINT8 ssplayers, boolean nowipe)
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
}
void M_LevelSelected(INT16 add, boolean menuupdate)
INT16 M_LevelFromScrolledList(INT16 add)
{
UINT8 i = 0;
INT16 map = M_GetFirstLevelInList(&i, &levellist.levelsearch);
@ -749,6 +753,13 @@ void M_LevelSelected(INT16 add, boolean menuupdate)
add--;
}
return map;
}
void M_LevelSelected(INT16 add, boolean menuupdate)
{
INT16 map = M_LevelFromScrolledList(add);
if (map >= nummapheaders)
{
// This shouldn't happen
@ -810,6 +821,82 @@ void M_LevelSelected(INT16 add, boolean menuupdate)
}
}
static void M_MenuQueueStopSend(INT32 ch)
{
(void)ch;
memset(&menuqueue, 0, sizeof(struct menuqueue));
}
static void M_MenuQueueSelectedLocal(void)
{
UINT8 i = 0;
for (; i < menuqueue.size; i++)
{
G_MapIntoRoundQueue(
menuqueue.entries[i].mapnum,
menuqueue.entries[i].gametype,
menuqueue.entries[i].encore,
false
);
}
roundqueue.netcommunicate = true;
if (gamestate == GS_MENU)
{
levellist.choosemap = roundqueue.entries[0].mapnum;
multiplayer = true;
M_MenuToLevelPreamble(
cv_splitplayers.value-1,
(
roundqueue.entries[0].encore
&& (gametypes[roundqueue.entries[0].gametype]->rules & GTR_ENCORE)
)
);
restoreMenu = (levellist.netgame)
? &PLAY_MP_OptSelectDef
: currentMenu;
restorelevellist = levellist;
roundqueue.position = roundqueue.roundnum = 1;
D_MapChange(
roundqueue.entries[0].mapnum + 1,
roundqueue.entries[0].gametype,
roundqueue.entries[0].encore,
true,
1,
false,
roundqueue.entries[0].rankrestricted
);
M_MenuQueueStopSend(MA_NONE);
M_ClearMenus(true);
}
else
{
if (gamestate == GS_LEVEL && roundqueue.position == 0)
{
menuqueue.sending = UINT8_MAX;
}
else
{
S_StartSound(NULL, sfx_chchng);
M_MenuQueueStopSend(MA_NONE);
M_ClearMenus(true);
}
}
}
boolean M_LevelSelectCupSwitch(boolean next, boolean skipones)
{
levelsearch_t templevelsearch = levellist.levelsearch;
@ -891,6 +978,44 @@ boolean M_LevelSelectCupSwitch(boolean next, boolean skipones)
}
}
static void M_MenuQueueResponse(INT32 ch)
{
M_ClearMenus(false);
if (ch != MA_YES)
return;
if (!(server || (IsPlayerAdmin(consoleplayer))))
return;
if (!(gamestate == GS_LEVEL && roundqueue.position == 0))
return;
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
static void M_ClearQueueResponse(INT32 ch)
{
if (ch != MA_YES)
return;
if (!(server || (IsPlayerAdmin(consoleplayer))))
return;
S_StartSound(NULL, sfx_slip);
if (netgame)
{
if (roundqueue.size)
{
Handle_MapQueueSend(0, ROUNDQUEUE_CMD_CLEAR, false);
}
return;
}
memset(&roundqueue, 0, sizeof(struct roundqueue));
}
void M_LevelSelectHandler(INT32 choice)
{
const UINT8 pid = 0;
@ -902,6 +1027,11 @@ void M_LevelSelectHandler(INT32 choice)
return;
}
if (menuqueue.sending)
{
return;
}
if (menucmd[pid].dpad_ud > 0)
{
levellist.cursor++;
@ -934,10 +1064,96 @@ void M_LevelSelectHandler(INT32 choice)
M_LevelSelectScrollDest();
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
if (M_MenuConfirmPressed(pid))
{
// Starting immediately OR importing queue
M_SetMenuDelay(pid);
M_LevelSelected(levellist.cursor, true);
while ((menuqueue.size + roundqueue.size) > ROUNDQUEUE_MAX)
menuqueue.size--;
if (!levellist.canqueue || !menuqueue.size)
{
M_LevelSelected(levellist.cursor, true);
}
else if (netgame)
{
menuqueue.anchor = roundqueue.size;
menuqueue.sending = 1;
M_StartMessage("Queueing Rounds",
va(M_GetText(
"Attempting to send %d Round%s...\n"
"\n"
"If this is taking longer than you\n"
"expect, exit out of this message.\n"
), menuqueue.size, (menuqueue.size == 1 ? "" : "s")
), &M_MenuQueueStopSend, MM_NOTHING,
NULL,
"This is taking too long..."
);
}
else
{
M_MenuQueueSelectedLocal();
}
}
else if (levellist.canqueue && M_MenuButtonPressed(pid, MBT_Z))
{
// Adding to queue
INT16 map = NEXTMAP_INVALID;
M_SetMenuDelay(pid);
if ((roundqueue.size + menuqueue.size) < ROUNDQUEUE_MAX)
{
map = M_LevelFromScrolledList(levellist.cursor);
}
if (map < nummapheaders)
{
memset(menuqueue.entries+menuqueue.size, 0, sizeof(roundentry_t));
menuqueue.entries[menuqueue.size].mapnum = map;
menuqueue.entries[menuqueue.size].gametype = levellist.newgametype;
menuqueue.entries[menuqueue.size].encore = (cv_kartencore.value == 1);
menuqueue.size++;
S_StartSound(NULL, sfx_s3k4a);
}
else
{
S_StartSound(NULL, sfx_s3kb2);
}
}
else if (levellist.canqueue && M_MenuExtraPressed(pid))
{
while ((menuqueue.size + roundqueue.size) > ROUNDQUEUE_MAX)
menuqueue.size--;
if (menuqueue.size)
{
S_StartSound(NULL, sfx_shldls);
menuqueue.size--;
}
else if (roundqueue.size)
{
M_StartMessage("Queue Clearing",
va(M_GetText(
"There %s %d Round%s of play queued.\n"
"\n"
"Do you want to empty the queue?\n"
),
(roundqueue.size == 1 ? "is" : "are"),
roundqueue.size,
(roundqueue.size == 1 ? "" : "s")
), &M_ClearQueueResponse, MM_YESNO,
"Time to start fresh",
"Not right now"
);
}
}
else if (M_MenuBackPressed(pid))
{
@ -952,4 +1168,55 @@ void M_LevelSelectHandler(INT32 choice)
void M_LevelSelectTick(void)
{
if (!menuqueue.sending)
return;
if ((menuqueue.sending <= menuqueue.size) // Sending
&& (roundqueue.size >= menuqueue.anchor)) // Didn't get it wiped
{
if (!netgame)
return;
const UINT8 idcount = (roundqueue.size - menuqueue.anchor);
if (idcount == menuqueue.sending-1)
{
Handle_MapQueueSend(
menuqueue.entries[idcount].mapnum,
menuqueue.entries[idcount].gametype,
menuqueue.entries[idcount].encore
);
}
if (idcount >= menuqueue.sending-1)
{
menuqueue.sending++;
}
return;
}
if (menuqueue.size)
{
S_StartSound(NULL, sfx_chchng);
if (roundqueue.position)
{
M_StopMessage(MA_NONE);
}
else
{
M_StartMessage("Round Queue",
va(M_GetText(
"You just queued %d Round%s of play.\n"
"\n"
"Do you want to skip the current\n"
"course and start them immediately?\n"
), menuqueue.size, (menuqueue.size == 1 ? "" : "s")
), &M_MenuQueueResponse, MM_YESNO,
"Let's get going!",
"Not right now"
);
}
}
M_MenuQueueStopSend(MA_NONE);
}

View file

@ -971,11 +971,15 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset)
// Handles drawing the bottom-of-screen progression.
// Currently requires intermission y_data for animation only.
//
void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations, boolean widescreen)
void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations, boolean widescreen, boolean adminmode)
{
if (roundqueue.size == 0)
{
return;
if (!adminmode
|| menuqueue.size == 0)
{
return;
}
}
// The following is functionally a hack.
@ -1041,6 +1045,10 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
prize_dot[BPP_AHEAD] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK4", PU_PATCH));
prize_dot[BPP_DONE] = static_cast<patch_t*>(W_CachePatchName("R_RRMRK6", PU_PATCH));
patch_t *rpmark[2];
rpmark[0] = static_cast<patch_t*>(W_CachePatchName("R_RPMARK", PU_PATCH));
rpmark[1] = static_cast<patch_t*>(W_CachePatchName("R_R2MARK", PU_PATCH));
UINT8 *colormap = NULL, *oppositemap = NULL;
fixed_t playerx = 0, playery = 0;
UINT8 pskin = MAXSKINS;
@ -1079,10 +1087,37 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
upwa = true;
}
workingqueuesize--;
if (!adminmode)
{
workingqueuesize--;
}
}
INT32 widthofroundqueue = 24*(workingqueuesize - 1);
INT32 widthofroundqueue, totalsteps;
INT32 menusendoffset = 0;
if (menuqueue.sending)
{
if (menuqueue.sending > menuqueue.size)
{
menusendoffset = menuqueue.size;
}
else
{
menusendoffset = menuqueue.sending-1;
}
}
if (adminmode)
{
totalsteps = std::min(workingqueuesize + (menuqueue.size - menusendoffset), ROUNDQUEUE_MAX);
}
else
{
totalsteps = workingqueuesize;
}
widthofroundqueue = (totalsteps - 1) * 24;
INT32 x = (BASEVIDWIDTH - widthofroundqueue) / 2;
INT32 y, basey = 167 + offset;
@ -1091,7 +1126,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
// The following block handles horizontal easing of the
// progression bar on the last non-rankrestricted round.
if (standings->showrank == true)
if (!adminmode && standings->showrank == true)
{
fixed_t percentslide = 0;
SINT8 deferxoffs = 0;
@ -1151,12 +1186,22 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
V_DrawMappedPatch(xiter, basey, baseflags, queuebg_upwa, greymap);
}
// Draw to left side of screen
while (xiter > -bufferspace)
{
xiter -= 24;
V_DrawMappedPatch(xiter, basey, baseflags, queuebg_flat, greymap);
}
// Draw to right side of screen
xiter = x + widthofroundqueue;
while (xiter < BASEVIDWIDTH + bufferspace)
{
xiter += 24;
V_DrawMappedPatch(xiter, basey, baseflags, queuebg_flat, greymap);
}
// Actually queued maps
for (i = 0; i < workingqueuesize; i++)
{
// Draw the background, and grab the appropriate line, to the right of the dot
@ -1186,7 +1231,13 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
}
else
{
V_DrawMappedPatch(x, basey, baseflags, queuebg_flat, greymap);
V_DrawMappedPatch(
x,
basey,
baseflags,
((workingqueuesize == totalsteps) ? queuebg_flat : queuebg_upwa),
greymap
);
}
}
@ -1321,17 +1372,9 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
}
else
{
// No more line! Fill in background to right edge of screen
xiter = x;
while (xiter < BASEVIDWIDTH + bufferspace)
{
xiter += 24;
V_DrawMappedPatch(xiter, basey, baseflags, queuebg_flat, greymap);
}
// Handle special entry on the end
// (has to be drawn before the semifinal dot due to overlap)
if (standings->showrank == true)
if (!adminmode && standings->showrank == true)
{
const fixed_t x2 = x + spacetospecial;
@ -1342,7 +1385,7 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
}
else if (
doanimations == true
&& roundqueue.position == roundqueue.size-1
&& roundqueue.position == workingqueuesize
&& timer - interpoffs <= 2*TICRATE
)
{
@ -1522,13 +1565,62 @@ void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations,
x += 24;
}
totalsteps -= i;
// Maps in the progress of being queued on the menu
if (adminmode && totalsteps)
{
for (i = menusendoffset; i < (totalsteps + menusendoffset); i++)
{
upwa ^= true;
if (upwa == false)
{
y = basey + 4;
V_DrawMappedPatch(x, basey, baseflags, queuebg_down, greymap);
}
else
{
y = basey + 12;
if (i+1 != menuqueue.size) // no more line?
{
V_DrawMappedPatch(x, basey, baseflags, queuebg_upwa, greymap);
}
else
{
V_DrawMappedPatch(x, basey, baseflags, queuebg_flat, greymap);
}
}
V_DrawMappedPatch(
x - 8, y,
baseflags,
level_dot[BPP_AHEAD],
NULL
);
V_DrawMappedPatch(
x - 10, y - 14,
baseflags,
rpmark[0],
NULL
);
K_DrawMapAsFace(
x - 9, y - 13,
(baseflags|((menuqueue.entries[i].encore) ? V_FLIP : 0)),
menuqueue.entries[i].mapnum,
NULL
);
x += 24;
}
}
// Draw the player position through the round queue!
if (playery != 0)
{
patch_t *rpmark[2];
rpmark[0] = static_cast<patch_t*>(W_CachePatchName("R_RPMARK", PU_PATCH));
rpmark[1] = static_cast<patch_t*>(W_CachePatchName("R_R2MARK", PU_PATCH));
// Change alignment
playerx -= (10 * FRACUNIT);
playery -= (14 * FRACUNIT);
@ -1934,7 +2026,7 @@ skiptallydrawer:
goto finalcounter;
// Returns early if there's no roundqueue entries to draw
Y_RoundQueueDrawer(&data, 0, true, false);
Y_RoundQueueDrawer(&data, 0, true, false, false);
if (netgame)
{

View file

@ -54,7 +54,7 @@ void Y_Ticker(void);
// Specific sub-drawers
void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset);
void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations, boolean widescreen);
void Y_RoundQueueDrawer(y_data_t *standings, INT32 offset, boolean doanimations, boolean widescreen, boolean adminmode);
void Y_DrawIntermissionButton(INT32 startslide, INT32 through, boolean widescreen);
void Y_DrawRankMode(INT32 x, INT32 y, boolean center);