mirror of
				https://github.com/KartKrewDev/RingRacers.git
				synced 2025-10-30 08:01:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			596 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			596 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // DR. ROBOTNIK'S RING RACERS
 | |
| //-----------------------------------------------------------------------------
 | |
| // Copyright (C) 2025 by Sally "TehRealSalt" Cochenour.
 | |
| // Copyright (C) 2025 by Vivian "toastergrl" Grannell.
 | |
| // Copyright (C) 2025 by Kart Krew.
 | |
| //
 | |
| // This program is free software distributed under the
 | |
| // terms of the GNU General Public License, version 2.
 | |
| // See the 'LICENSE' file for more details.
 | |
| //-----------------------------------------------------------------------------
 | |
| /// \file  menus/transient/cup-select.c
 | |
| /// \brief Cup Select
 | |
| 
 | |
| #include "../../i_time.h"
 | |
| #include "../../k_menu.h"
 | |
| #include "../../s_sound.h"
 | |
| #include "../../f_finale.h" // F_WipeStartScreen
 | |
| #include "../../v_video.h"
 | |
| #include "../../k_grandprix.h"
 | |
| #include "../../r_local.h" // SplitScreen_OnChange
 | |
| #include "../../k_podium.h" // K_StartCeremony
 | |
| #include "../../m_misc.h" // FIL_FileExists
 | |
| #include "../../d_main.h" // D_ClearState
 | |
| #include "../../m_cond.h" // Condition Sets
 | |
| 
 | |
| menuitem_t PLAY_CupSelect[] =
 | |
| {
 | |
| 	{IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, {.routine = M_CupSelectHandler}, 0, 0},
 | |
| };
 | |
| 
 | |
| menu_t PLAY_CupSelectDef = {
 | |
| 	sizeof(PLAY_CupSelect) / sizeof(menuitem_t),
 | |
| 	&PLAY_RaceGamemodesDef,
 | |
| 	0,
 | |
| 	PLAY_CupSelect,
 | |
| 	0, 0,
 | |
| 	0, 0,
 | |
| 	0,
 | |
| 	NULL,
 | |
| 	2, 5,
 | |
| 	M_DrawCupSelect,
 | |
| 	NULL,
 | |
| 	M_CupSelectTick,
 | |
| 	NULL,
 | |
| 	NULL,
 | |
| 	NULL
 | |
| };
 | |
| 
 | |
| struct cupgrid_s cupgrid;
 | |
| 
 | |
| static void M_StartCup(UINT8 entry)
 | |
| {
 | |
| 	UINT8 ssplayers = cv_splitplayers.value-1;
 | |
| 
 | |
| 	if (ssplayers > 0)
 | |
| 	{
 | |
| 		// Splitscreen is not accomodated with this recovery feature.
 | |
| 		entry = UINT8_MAX;
 | |
| 	}
 | |
| 
 | |
| 	M_MenuToLevelPreamble(ssplayers, false);
 | |
| 
 | |
| 	if (entry == UINT8_MAX)
 | |
| 	{
 | |
| 		entry = 0;
 | |
| 		memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
 | |
| 
 | |
| 		// read our dummy cvars
 | |
| 
 | |
| 		grandprixinfo.gamespeed = min(KARTSPEED_HARD, cv_dummygpdifficulty.value);
 | |
| 		grandprixinfo.masterbots = (cv_dummygpdifficulty.value == 3);
 | |
| 
 | |
| 		grandprixinfo.gp = true;
 | |
| 		grandprixinfo.initalize = true;
 | |
| 		grandprixinfo.cup = levellist.levelsearch.cup;
 | |
| 
 | |
| 		// Populate the roundqueue
 | |
| 		memset(&roundqueue, 0, sizeof(struct roundqueue));
 | |
| 		G_GPCupIntoRoundQueue(levellist.levelsearch.cup, levellist.newgametype,
 | |
| #if 0 // TODO: encore GP
 | |
| 			(boolean)cv_dummygpencore.value
 | |
| #else
 | |
| 			false
 | |
| #endif
 | |
| 		);
 | |
| 		roundqueue.position = roundqueue.roundnum = 1;
 | |
| 		roundqueue.netcommunicate = true; // relevant for future Online GP
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		// Silently change player setup
 | |
| 		{
 | |
| 			CV_StealthSetValue(&cv_playercolor[0], savedata.skincolor);
 | |
| 
 | |
| 			// follower
 | |
| 			if (savedata.followerskin < 0 || savedata.followerskin >= numfollowers)
 | |
| 				CV_StealthSet(&cv_follower[0], "None");
 | |
| 			else
 | |
| 				CV_StealthSet(&cv_follower[0], followers[savedata.followerskin].name);
 | |
| 
 | |
| 			// finally, call the skin[x] console command.
 | |
| 			// This will call SendNameAndColor which will synch everything we sent here and apply the changes!
 | |
| 
 | |
| 			CV_StealthSet(&cv_skin[0], skins[savedata.skin]->name);
 | |
| 
 | |
| 			// ...actually, let's do this last - Skin_OnChange has some return-early occasions
 | |
| 			// follower color
 | |
| 			CV_SetValue(&cv_followercolor[0], savedata.followercolor);
 | |
| 		}
 | |
| 
 | |
| 		// Skip Bonus rounds.
 | |
| 		if (roundqueue.entries[entry].gametype != GT_RACE // roundqueue.entries[0].gametype
 | |
| 			&& roundqueue.entries[entry].rankrestricted == false)
 | |
| 		{
 | |
| 			G_GetNextMap(); // updates position in the roundqueue
 | |
| 			entry = roundqueue.position-1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	M_ClearMenus(true);
 | |
| 
 | |
| 	restoreMenu = &PLAY_CupSelectDef;
 | |
| 	restorelevellist = levellist;
 | |
| 
 | |
| 	if (entry < roundqueue.size)
 | |
| 	{
 | |
| 		D_MapChange(
 | |
| 			roundqueue.entries[entry].mapnum + 1,
 | |
| 			roundqueue.entries[entry].gametype,
 | |
| 			roundqueue.entries[entry].encore,
 | |
| 			true,
 | |
| 			1,
 | |
| 			false,
 | |
| 			roundqueue.entries[entry].rankrestricted
 | |
| 		);
 | |
| 	}
 | |
| 	else if (entry == 0)
 | |
| 	{
 | |
| 		I_Error("M_StartCup: roundqueue is empty on startup!!");
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (K_StartCeremony() == false)
 | |
| 		{
 | |
| 			// Accomodate our buffoonery
 | |
| 			D_ClearState();
 | |
| 			M_StartControlPanel();
 | |
| 
 | |
| 			M_StartMessage(
 | |
| 				"Grand Prix Backup",
 | |
| 				"The session is concluded!\n"
 | |
| 				"You exited a final Bonus Round,\n"
 | |
| 				"and the Podium failed to load.\n",
 | |
| 				NULL, MM_NOTHING, NULL, NULL
 | |
| 			);
 | |
| 
 | |
| 			if (FIL_FileExists(gpbackup))
 | |
| 				remove(gpbackup);
 | |
| 
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static UINT16 cupselecttutorial_hack = NEXTMAP_INVALID;
 | |
| 
 | |
| static void M_GPTutorialResponse(INT32 choice)
 | |
| {
 | |
| 	if (choice != MA_YES)
 | |
| 		return;
 | |
| 
 | |
| 	multiplayer = true;
 | |
| 
 | |
| 	restoreMenu = &PLAY_CupSelectDef;
 | |
| 	restorelevellist = levellist;
 | |
| 
 | |
| 	// mild hack
 | |
| 	levellist.newgametype = GT_TUTORIAL;
 | |
| 	levellist.netgame = false;
 | |
| 	M_MenuToLevelPreamble(0, false);
 | |
| 
 | |
| 	D_MapChange(
 | |
| 		cupselecttutorial_hack+1,
 | |
| 		levellist.newgametype,
 | |
| 		false,
 | |
| 		true,
 | |
| 		1,
 | |
| 		false,
 | |
| 		false
 | |
| 	);
 | |
| 
 | |
| 	M_ClearMenus(true);
 | |
| }
 | |
| 
 | |
| static boolean M_GPTutorialRecommendation(cupheader_t *cup)
 | |
| {
 | |
| 	// Only applies to GP.
 | |
| 	if (levellist.levelsearch.grandprix == false)
 | |
| 		return false;
 | |
| 
 | |
| 	// Does this not have a Tutorial Recommendation?
 | |
| 	if (cup->cache_cuplock >= MAXUNLOCKABLES
 | |
| 	|| cup->hintcondition == MAXCONDITIONSETS
 | |
| 	|| !M_Achieved(cup->hintcondition))
 | |
| 		return false;
 | |
| 
 | |
| 	// Does the thing have no condition?
 | |
| 	const UINT16 condition = unlockables[cup->cache_cuplock].conditionset;
 | |
| 	if (condition == 0)
 | |
| 		return false;
 | |
| 
 | |
| 	const conditionset_t *c = &conditionSets[condition-1];
 | |
| 	UINT32 i;
 | |
| 	INT32 mapnum = NEXTMAP_INVALID;
 | |
| 
 | |
| 	// Identify the map to visit/beat.
 | |
| 	for (i = 0; i < c->numconditions; ++i)
 | |
| 	{
 | |
| 		if (c->condition[i].type < UC_MAPVISITED || c->condition[i].type > UC_MAPBEATEN)
 | |
| 			continue;
 | |
| 		mapnum = c->condition[i].requirement;
 | |
| 		if (mapnum < 0 || mapnum >= nummapheaders)
 | |
| 			continue;
 | |
| 		if (!mapheaderinfo[mapnum])
 | |
| 			continue;
 | |
| 		if (G_GuessGametypeByTOL(mapheaderinfo[mapnum]->typeoflevel) != GT_TUTORIAL)
 | |
| 			continue;
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	// Didn't find one?
 | |
| 	if (i == c->numconditions)
 | |
| 		return false;
 | |
| 
 | |
| 	// Not unlocked?
 | |
| 	if (M_MapLocked(mapnum+1))
 | |
| 	{
 | |
| 		M_StartMessage(
 | |
| 			"Recommended Learning",
 | |
| 			"This Cup will test skills that\n"
 | |
| 			"a ""\x86""currently locked ""\x87""Tutorial\x80 teaches.\n"
 | |
| 			"\n"
 | |
| 			"Come back when you've made progress elsewhere.",
 | |
| 			NULL, MM_NOTHING, NULL, NULL
 | |
| 		);
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	// This is kind of a hack.
 | |
| 	cupselecttutorial_hack = mapnum;
 | |
| 
 | |
| 	M_StartMessage(
 | |
| 		"Recommended Learning",
 | |
| 		va(
 | |
| 		"This Cup will test skills that\n"
 | |
| 		"the ""\x87""%s Tutorial\x80 teaches.\n"
 | |
| 		"\n"
 | |
| 		"%s\n",
 | |
| 		mapheaderinfo[mapnum]->menuttl,
 | |
| 		(setup_numplayers > 1
 | |
| 			? "You're encouraged to play it later."
 | |
| 			: "Would you like to play it now?"
 | |
| 		)),
 | |
| 		setup_numplayers > 1 ? NULL : M_GPTutorialResponse,
 | |
| 		setup_numplayers > 1 ? MM_NOTHING : MM_YESNO,
 | |
| 		setup_numplayers > 1 ? NULL : "Yes, let's go",
 | |
| 		setup_numplayers > 1 ? "Got it!" : "Not right now"
 | |
| 	);
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static void M_GPBackup(INT32 choice)
 | |
| {
 | |
| 	if (choice == MA_YES)
 | |
| 	{
 | |
| 		G_LoadGame();
 | |
| 
 | |
| 		if (savedata.lives != 0)
 | |
| 		{
 | |
| 			M_StartCup(roundqueue.position-1);
 | |
| 		}
 | |
| 
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	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;
 | |
| 
 | |
| 	(void)choice;
 | |
| 
 | |
| 	if (menucmd[pid].dpad_lr > 0)
 | |
| 	{
 | |
| 		cupgrid.x++;
 | |
| 		if (cupgrid.x >= CUPMENU_COLUMNS)
 | |
| 		{
 | |
| 			cupgrid.x = 0;
 | |
| 			cupgrid.pageno++;
 | |
| 			if (cupgrid.pageno >= cupgrid.numpages)
 | |
| 				cupgrid.pageno = 0;
 | |
| 		}
 | |
| 		cupgrid.xslide.start = I_GetTime();
 | |
| 		cupgrid.xslide.dist = 42;
 | |
| 		S_StartSound(NULL, sfx_s3k5b);
 | |
| 		M_SetMenuDelay(pid);
 | |
| 	}
 | |
| 	else if (menucmd[pid].dpad_lr < 0)
 | |
| 	{
 | |
| 		cupgrid.x--;
 | |
| 		if (cupgrid.x < 0)
 | |
| 		{
 | |
| 			cupgrid.x = CUPMENU_COLUMNS-1;
 | |
| 			if (cupgrid.pageno == 0)
 | |
| 				cupgrid.pageno = cupgrid.numpages-1;
 | |
| 			else
 | |
| 				cupgrid.pageno--;
 | |
| 		}
 | |
| 		cupgrid.xslide.start = I_GetTime();
 | |
| 		cupgrid.xslide.dist = -42;
 | |
| 		S_StartSound(NULL, sfx_s3k5b);
 | |
| 		M_SetMenuDelay(pid);
 | |
| 	}
 | |
| 
 | |
| 	if (cupgrid.cache_secondrowlocked == true)
 | |
| 		; // No up/down for you!
 | |
| 	else if (menucmd[pid].dpad_ud > 0)
 | |
| 	{
 | |
| 		cupgrid.y++;
 | |
| 		if (cupgrid.y >= CUPMENU_ROWS)
 | |
| 		{
 | |
| 			cupgrid.y = 0;
 | |
| 			cupgrid.yslide.dist = 8;
 | |
| 		}
 | |
| 		else
 | |
| 			cupgrid.yslide.dist = 44;
 | |
| 		cupgrid.yslide.start = I_GetTime();
 | |
| 		S_StartSound(NULL, sfx_s3k5b);
 | |
| 		M_SetMenuDelay(pid);
 | |
| 	}
 | |
| 	else if (menucmd[pid].dpad_ud < 0)
 | |
| 	{
 | |
| 		cupgrid.y--;
 | |
| 		if (cupgrid.y < 0)
 | |
| 		{
 | |
| 			cupgrid.y = CUPMENU_ROWS-1;
 | |
| 			cupgrid.yslide.dist = -8;
 | |
| 		}
 | |
| 		else
 | |
| 			cupgrid.yslide.dist = -44;
 | |
| 		cupgrid.yslide.start = I_GetTime();
 | |
| 		S_StartSound(NULL, sfx_s3k5b);
 | |
| 		M_SetMenuDelay(pid);
 | |
| 	}
 | |
| 
 | |
| 	if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
 | |
| 	{
 | |
| 		UINT16 count;
 | |
| 		cupheader_t *newcup = cupgrid.builtgrid[CUPMENU_CURSORID];
 | |
| 		cupheader_t *oldcup = levellist.levelsearch.cup;
 | |
| 
 | |
| 		M_SetMenuDelay(pid);
 | |
| 
 | |
| 		if (!newcup)
 | |
| 		{
 | |
| 			S_StartSound(NULL, sfx_s3kb2);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		levellist.levelsearch.cup = newcup;
 | |
| 		count = M_CountLevelsToShowInList(&levellist.levelsearch);
 | |
| 
 | |
| 		if (count == 0
 | |
| 			|| (
 | |
| 				levellist.levelsearch.grandprix == true
 | |
| 				&& newcup->cachedlevels[0] == NEXTMAP_INVALID
 | |
| 			)
 | |
| 		)
 | |
| 		{
 | |
| 			if (!M_GPTutorialRecommendation(newcup))
 | |
| 				S_StartSound(NULL, sfx_s3kb2);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (levellist.levelsearch.grandprix == true)
 | |
| 		{
 | |
| 			if (newcup == cupsavedata.cup
 | |
| 			&& FIL_FileExists(gpbackup))
 | |
| 			{
 | |
| 				M_StartMessage(
 | |
| 					"Grand Prix Backup",
 | |
| 					"A progress backup was found.\n"
 | |
| 					"Do you want to resurrect your\n"
 | |
| 					"last Grand Prix session?\n",
 | |
| 					M_GPBackup,
 | |
| 					MM_YESNO,
 | |
| 					"Yes, let's try again",
 | |
| 					"No, start from Round 1"
 | |
| 				);
 | |
| 
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			M_StartCup(UINT8_MAX);
 | |
| 		}
 | |
| 		else if (count == 1 && levellist.levelsearch.timeattack == true)
 | |
| 		{
 | |
| 			currentMenu->transitionID = PLAY_TimeAttackDef.transitionID+1;
 | |
| 			M_LevelSelected(0, true);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			currentMenu->transitionID = PLAY_LevelSelectDef.transitionID;
 | |
| 
 | |
| 			// Keep cursor position if you select the same cup again, reset if it's a different cup
 | |
| 			if (oldcup != newcup || levellist.cursor >= count)
 | |
| 			{
 | |
| 				levellist.cursor = 0;
 | |
| 			}
 | |
| 
 | |
| 			levellist.mapcount = count;
 | |
| 			M_LevelSelectScrollDest();
 | |
| 			levellist.slide.start = 0;
 | |
| 
 | |
| 			M_SetupNextMenu(&PLAY_LevelSelectDef, false);
 | |
| 			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) || (cupgrid.builtgrid[CUPMENU_CURSORID] == NULL))
 | |
| 			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);
 | |
| 
 | |
| 		if (currentMenu->prevMenu)
 | |
| 			M_SetupNextMenu(currentMenu->prevMenu, false);
 | |
| 		else
 | |
| 			M_ClearMenus(true);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void M_CupSelectTick(void)
 | |
| {
 | |
| 	cupgrid.previewanim++;
 | |
| 	// Shoving this here for cup queue purposes.
 | |
| 	M_LevelSelectTick();
 | |
| }
 | 
