mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Add ability to queue all maps in a cup for netgames and local matches by pressing Action on cup select.
This commit is contained in:
parent
6fcfd452aa
commit
188d168ace
5 changed files with 355 additions and 65 deletions
|
|
@ -81,6 +81,8 @@ extern struct menuqueue
|
|||
UINT8 size;
|
||||
UINT8 sending;
|
||||
UINT8 anchor;
|
||||
boolean clearing;
|
||||
boolean cupqueue;
|
||||
roundentry_t entries[ROUNDQUEUE_MAX];
|
||||
} menuqueue;
|
||||
|
||||
|
|
|
|||
|
|
@ -961,6 +961,10 @@ void M_MenuToLevelPreamble(UINT8 ssplayers, boolean nowipe);
|
|||
void M_LevelSelected(INT16 add, boolean menuupdate);
|
||||
boolean M_LevelSelectCupSwitch(boolean next, boolean skipones);
|
||||
|
||||
void M_LevelConfirmHandler(void);
|
||||
void M_ClearQueueHandler(void);
|
||||
void M_CupQueueHandler(cupheader_t *cup);
|
||||
|
||||
// dummy consvars for GP & match race setup
|
||||
extern consvar_t cv_dummygpdifficulty;
|
||||
extern consvar_t cv_dummykartspeed;
|
||||
|
|
|
|||
|
|
@ -3340,6 +3340,21 @@ void M_DrawCupSelect(void)
|
|||
M_DrawCupPreview(y, &templevelsearch);
|
||||
|
||||
M_DrawCupTitle(120 - ty, &templevelsearch);
|
||||
|
||||
const char *worktext = "Undo";
|
||||
|
||||
if (menuqueue.size)
|
||||
worktext = "Undo";
|
||||
else if (roundqueue.size)
|
||||
worktext = "Clear Queue";
|
||||
|
||||
if (levellist.canqueue)
|
||||
{
|
||||
K_DrawGameControl(BASEVIDWIDTH/2, 6-ty, 0, va("%s Queue Cup<white> %s %s",
|
||||
(templevelsearch.cup && templevelsearch.cup != &dummy_lostandfound && !roundqueue.size) ? "<z_animated>" : "<z_pressed><gray>",
|
||||
(roundqueue.size || menuqueue.size) ? "<c_animated>" : "<c_pressed><gray>",
|
||||
worktext), 1, TINY_FONT, 0);
|
||||
}
|
||||
|
||||
if (templevelsearch.grandprix == false && templevelsearch.cup != NULL)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -287,6 +287,97 @@ static void M_GPBackup(INT32 choice)
|
|||
M_StartCup(UINT8_MAX);
|
||||
}
|
||||
|
||||
static boolean M_IsCupQueueable(cupheader_t *cup)
|
||||
{
|
||||
levelsearch_t templevelsearch = levellist.levelsearch; // copy levellist so we don't mess with stuff I think
|
||||
UINT16 ShownCount = 0;
|
||||
UINT16 CupCount = 0;
|
||||
UINT32 CheckGametype[2] = {TOL_RACE,TOL_BATTLE};
|
||||
|
||||
templevelsearch.cup = cup;
|
||||
|
||||
UINT8 e, i = 0;
|
||||
for (e = 0; e < 2; e++)
|
||||
{
|
||||
templevelsearch.typeoflevel = CheckGametype[e];
|
||||
ShownCount += M_CountLevelsToShowInList(&templevelsearch);
|
||||
}
|
||||
//CONS_Printf(M_GetText("ShownCount: %d\n"), ShownCount);
|
||||
UINT16 checkmap = NEXTMAP_INVALID;
|
||||
for (i = 0; i < CUPCACHE_SPECIAL; i++)
|
||||
{
|
||||
checkmap = templevelsearch.cup->cachedlevels[i];
|
||||
if (checkmap == NEXTMAP_INVALID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CupCount++;
|
||||
}
|
||||
//CONS_Printf(M_GetText("CupCount: %d\n"), CupCount);
|
||||
if (ShownCount >= CupCount) // greater than is used to ensure multi-gametype maps don't accidentally cause this to return false.
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void M_CupStartResponse(INT32 ch)
|
||||
{
|
||||
if (ch != MA_YES)
|
||||
return;
|
||||
|
||||
if (!(server || (IsPlayerAdmin(consoleplayer))))
|
||||
return;
|
||||
|
||||
M_LevelConfirmHandler();
|
||||
}
|
||||
|
||||
static void M_CupQueueResponse(INT32 ch)
|
||||
{
|
||||
if (ch != MA_YES)
|
||||
return;
|
||||
|
||||
if (!(server || (IsPlayerAdmin(consoleplayer))))
|
||||
return;
|
||||
|
||||
cupheader_t *queuedcup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||
|
||||
M_CupQueueHandler(queuedcup);
|
||||
|
||||
S_StartSound(NULL, sfx_gshe2);
|
||||
|
||||
while ((menuqueue.size + roundqueue.size) > ROUNDQUEUE_MAX)
|
||||
menuqueue.size--;
|
||||
|
||||
if (!netgame)
|
||||
{
|
||||
M_StartMessage("Cup Queue",
|
||||
va(M_GetText(
|
||||
"You just queued %s CUP.\n"
|
||||
"\n"
|
||||
"Do you want to start the\n"
|
||||
"cup immediately?\n"
|
||||
), queuedcup->realname
|
||||
), &M_CupStartResponse, MM_YESNO,
|
||||
"Here we go!",
|
||||
"On second thought..."
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
M_StartMessage("Cup Queue",
|
||||
va(M_GetText(
|
||||
"You just queued %s CUP.\n"
|
||||
"\n"
|
||||
"Do you want to queue it\n"
|
||||
"for everyone?\n"
|
||||
), queuedcup->realname
|
||||
), &M_CupStartResponse, MM_YESNO,
|
||||
"Queue em up!",
|
||||
"Not yet"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void M_CupSelectHandler(INT32 choice)
|
||||
{
|
||||
const UINT8 pid = 0;
|
||||
|
|
@ -429,6 +520,63 @@ void M_CupSelectHandler(INT32 choice)
|
|||
S_StartSound(NULL, sfx_s3k63);
|
||||
}
|
||||
}
|
||||
// Queue a cup for match race and netgames. See levelselect.c for most of how this actually works.
|
||||
else if (levellist.canqueue && M_MenuButtonPressed(pid, MBT_Z))
|
||||
{
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
if (cupgrid.builtgrid[CUPMENU_CURSORID] == &dummy_lostandfound)
|
||||
S_StartSound(NULL, sfx_gshe7);
|
||||
|
||||
else if (!M_IsCupQueueable(cupgrid.builtgrid[CUPMENU_CURSORID]))
|
||||
{
|
||||
S_StartSound(NULL, sfx_s3kb2);
|
||||
M_StartMessage("Back to the Grand Prix!", "Can't queue a cup you haven't fully unlocked!", NULL, MM_NOTHING, NULL, NULL);
|
||||
}
|
||||
|
||||
// Better to avoid any headaches here - pass the buck to the Extra button.
|
||||
else if (roundqueue.size)
|
||||
{
|
||||
S_StartSound(NULL, sfx_s3kb2);
|
||||
M_StartMessage("Queue is not empty!", "Clear the queue before trying to queue a cup!", NULL, MM_NOTHING, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// We're not queueing Battle maps if we're in single-player Match Race.
|
||||
if (!levellist.netgame && (cv_splitplayers.value == 1) && !netgame)
|
||||
{
|
||||
M_StartMessage("Cup Queue",
|
||||
va(M_GetText(
|
||||
"This will queue all Race courses in this cup.\n"
|
||||
"\n"
|
||||
"Any rounds already in the queue will be cleared out.\n"
|
||||
"\n"
|
||||
"Do you want to queue the cup?\n"
|
||||
)), &M_CupQueueResponse, MM_YESNO,
|
||||
"Let's do it!",
|
||||
"Nah.");
|
||||
}
|
||||
else
|
||||
{
|
||||
M_StartMessage("Cup Queue",
|
||||
va(M_GetText(
|
||||
"This will queue the entire cup, including both Race and Battle courses.\n"
|
||||
"\n"
|
||||
"Any rounds already in the queue will be cleared out.\n"
|
||||
"\n"
|
||||
"Do you want to queue the cup?\n"
|
||||
)), &M_CupQueueResponse, MM_YESNO,
|
||||
"Let's do it!",
|
||||
"Nah.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (levellist.canqueue && M_MenuExtraPressed(pid))
|
||||
{
|
||||
M_ClearQueueHandler();
|
||||
}
|
||||
else if (M_MenuBackPressed(pid))
|
||||
{
|
||||
M_SetMenuDelay(pid);
|
||||
|
|
@ -443,4 +591,6 @@ void M_CupSelectHandler(INT32 choice)
|
|||
void M_CupSelectTick(void)
|
||||
{
|
||||
cupgrid.previewanim++;
|
||||
// Shoving this here for cup queue purposes.
|
||||
M_LevelSelectTick();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -832,8 +832,10 @@ void M_LevelSelected(INT16 add, boolean menuupdate)
|
|||
static void M_MenuQueueStopSend(INT32 ch)
|
||||
{
|
||||
(void)ch;
|
||||
|
||||
|
||||
memset(&menuqueue, 0, sizeof(struct menuqueue));
|
||||
|
||||
menuqueue.clearing = false;
|
||||
}
|
||||
|
||||
static void M_MenuQueueSelectedLocal(void)
|
||||
|
|
@ -905,6 +907,92 @@ static void M_MenuQueueSelectedLocal(void)
|
|||
}
|
||||
}
|
||||
|
||||
// Copy-pasted and edited from G_GPCupIntoRoundQueue
|
||||
void M_CupQueueHandler(cupheader_t *cup)
|
||||
{
|
||||
UINT8 i, levelindex = 0, bonusindex = 0;
|
||||
UINT8 bonusmodulo = max(1, (cup->numlevels+1)/(cup->numbonus+1));
|
||||
UINT16 cupLevelNum;
|
||||
INT32 gtcheck;
|
||||
|
||||
// We shouldn't get to this point while there's rounds queued, but if we do, get outta there.
|
||||
if (roundqueue.size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
menuqueue.size = 0;
|
||||
|
||||
// Levels are added to the queue in the following pattern.
|
||||
// For 5 Race rounds and 2 Bonus rounds, the most common case:
|
||||
// race - race - BONUS - race - race - BONUS - race
|
||||
// The system is flexible enough to permit other arrangements.
|
||||
// However, we just want to keep the pacing even & consistent.
|
||||
while (levelindex < cup->numlevels)
|
||||
{
|
||||
memset(menuqueue.entries+menuqueue.size, 0, sizeof(roundentry_t));
|
||||
|
||||
// Fill like two or three Race maps.
|
||||
for (i = 0; i < bonusmodulo; i++)
|
||||
{
|
||||
cupLevelNum = cup->cachedlevels[levelindex];
|
||||
|
||||
if (cupLevelNum >= nummapheaders)
|
||||
{
|
||||
// Just skip the map if it's invalid.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((mapheaderinfo[cupLevelNum]->typeoflevel & TOL_RACE) == TOL_RACE)
|
||||
{
|
||||
gtcheck = GT_RACE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gtcheck = mapheaderinfo[cupLevelNum]->typeoflevel;
|
||||
}
|
||||
|
||||
menuqueue.entries[menuqueue.size].mapnum = cupLevelNum;
|
||||
menuqueue.entries[menuqueue.size].gametype = gtcheck;
|
||||
menuqueue.entries[menuqueue.size].encore = (cv_kartencore.value == 1);
|
||||
|
||||
menuqueue.size++;
|
||||
|
||||
levelindex++;
|
||||
if (levelindex >= cup->numlevels)
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to add an interstitial Battle round.
|
||||
// If we're in singleplayer Match Race, just skip this.
|
||||
if ((levelindex < cup->numlevels
|
||||
&& bonusindex < cup->numbonus) && (levellist.netgame || (cv_splitplayers.value > 1) || netgame))
|
||||
{
|
||||
cupLevelNum = cup->cachedlevels[CUPCACHE_BONUS + bonusindex];
|
||||
|
||||
if (cupLevelNum < nummapheaders)
|
||||
{
|
||||
if ((mapheaderinfo[cupLevelNum]->typeoflevel & TOL_BATTLE) == TOL_BATTLE)
|
||||
{
|
||||
gtcheck = GT_BATTLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gtcheck = mapheaderinfo[cupLevelNum]->typeoflevel;
|
||||
}
|
||||
// In the case of Bonus rounds, we simply skip invalid maps.
|
||||
menuqueue.entries[menuqueue.size].mapnum = cupLevelNum;
|
||||
menuqueue.entries[menuqueue.size].gametype = gtcheck;
|
||||
menuqueue.entries[menuqueue.size].encore = (cv_kartencore.value == 1);
|
||||
|
||||
menuqueue.size++;
|
||||
}
|
||||
|
||||
bonusindex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean M_LevelSelectCupSwitch(boolean next, boolean skipones)
|
||||
{
|
||||
levelsearch_t templevelsearch = levellist.levelsearch;
|
||||
|
|
@ -1002,6 +1090,40 @@ static void M_MenuQueueResponse(INT32 ch)
|
|||
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
|
||||
}
|
||||
|
||||
// Ripped out of LevelSelectHandler for use in cup queueing from cupselect.c
|
||||
void M_LevelConfirmHandler(void)
|
||||
{
|
||||
// Starting immediately OR importing queue
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
static void M_ClearQueueResponse(INT32 ch)
|
||||
{
|
||||
|
|
@ -1012,18 +1134,56 @@ static void M_ClearQueueResponse(INT32 ch)
|
|||
return;
|
||||
|
||||
S_StartSound(NULL, sfx_slip);
|
||||
|
||||
if (netgame)
|
||||
|
||||
if (!netgame)
|
||||
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||
if (netgame && (roundqueue.size != 0))
|
||||
{
|
||||
if (roundqueue.size)
|
||||
{
|
||||
Handle_MapQueueSend(0, ROUNDQUEUE_CMD_CLEAR, false);
|
||||
}
|
||||
return;
|
||||
menuqueue.clearing = true;
|
||||
Handle_MapQueueSend(0, ROUNDQUEUE_CMD_CLEAR, false);
|
||||
M_StartMessage("Clearing Rounds",
|
||||
va(M_GetText(
|
||||
"Attempting to clear %d Round%s...\n"
|
||||
"\n"
|
||||
"If this is taking longer than you\n"
|
||||
"expect, exit out of this message.\n"
|
||||
), roundqueue.size, (roundqueue.size == 1 ? "" : "s")
|
||||
), &M_MenuQueueStopSend, MM_NOTHING,
|
||||
NULL,
|
||||
"This is taking too long..."
|
||||
);
|
||||
}
|
||||
|
||||
memset(&roundqueue, 0, sizeof(struct roundqueue));
|
||||
}
|
||||
|
||||
// Ripped out of LevelSelectHandler for use in queue clearing from cupselect.c
|
||||
void M_ClearQueueHandler(void)
|
||||
{
|
||||
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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void M_LevelSelectHandler(INT32 choice)
|
||||
{
|
||||
const UINT8 pid = 0;
|
||||
|
|
@ -1074,38 +1234,9 @@ void M_LevelSelectHandler(INT32 choice)
|
|||
|
||||
if (M_MenuConfirmPressed(pid))
|
||||
{
|
||||
// Starting immediately OR importing queue
|
||||
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
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();
|
||||
}
|
||||
M_LevelConfirmHandler();
|
||||
}
|
||||
else if (levellist.canqueue && M_MenuButtonPressed(pid, MBT_Z))
|
||||
{
|
||||
|
|
@ -1138,30 +1269,7 @@ void M_LevelSelectHandler(INT32 choice)
|
|||
}
|
||||
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"
|
||||
);
|
||||
}
|
||||
M_ClearQueueHandler();
|
||||
}
|
||||
else if (M_MenuBackPressed(pid))
|
||||
{
|
||||
|
|
@ -1176,9 +1284,20 @@ void M_LevelSelectHandler(INT32 choice)
|
|||
|
||||
void M_LevelSelectTick(void)
|
||||
{
|
||||
if (menuqueue.clearing)
|
||||
{
|
||||
if (roundqueue.size != 0)
|
||||
return;
|
||||
menuqueue.clearing = false;
|
||||
if (!menuqueue.cupqueue)
|
||||
M_StopMessage(MA_NONE);
|
||||
else
|
||||
menuqueue.cupqueue = false;
|
||||
}
|
||||
|
||||
if (!menuqueue.sending)
|
||||
return;
|
||||
|
||||
|
||||
if ((menuqueue.sending <= menuqueue.size) // Sending
|
||||
&& (roundqueue.size >= menuqueue.anchor)) // Didn't get it wiped
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue