mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
"Special" time attack mode for 1P.
* Both GT_SPECIAL and GT_VERSUS.
* Access controlled by SECRET_SPECIALATTACK. (You're blue now.)
Related changes to precipitate:
* Cups that only have one map in them get selected immediately, rather than off-the-cuff.
* Done by seperating out a new function M_LevelSelected from M_LevelSelectHandler
* Maps that only have one lap in them don't have a visible lap timestamp sticker.
* Fix a cup with *no* valid maps for the current ruleset being hypothetically selectable
This commit is contained in:
parent
15587417c7
commit
04f2ac4121
6 changed files with 162 additions and 104 deletions
|
|
@ -2260,6 +2260,8 @@ void readunlockable(MYFILE *f, INT32 num)
|
||||||
unlockables[num].type = SECRET_TIMEATTACK;
|
unlockables[num].type = SECRET_TIMEATTACK;
|
||||||
else if (fastcmp(word2, "BREAKTHECAPSULES"))
|
else if (fastcmp(word2, "BREAKTHECAPSULES"))
|
||||||
unlockables[num].type = SECRET_BREAKTHECAPSULES;
|
unlockables[num].type = SECRET_BREAKTHECAPSULES;
|
||||||
|
else if (fastcmp(word2, "SPECIALATTACK"))
|
||||||
|
unlockables[num].type = SECRET_SPECIALATTACK;
|
||||||
else if (fastcmp(word2, "SOUNDTEST"))
|
else if (fastcmp(word2, "SOUNDTEST"))
|
||||||
unlockables[num].type = SECRET_SOUNDTEST;
|
unlockables[num].type = SECRET_SOUNDTEST;
|
||||||
else if (fastcmp(word2, "ALTTITLE"))
|
else if (fastcmp(word2, "ALTTITLE"))
|
||||||
|
|
|
||||||
|
|
@ -709,6 +709,7 @@ extern struct levellist_s {
|
||||||
UINT16 dest;
|
UINT16 dest;
|
||||||
INT16 choosemap;
|
INT16 choosemap;
|
||||||
UINT8 newgametype;
|
UINT8 newgametype;
|
||||||
|
UINT8 guessgt;
|
||||||
levelsearch_t levelsearch;
|
levelsearch_t levelsearch;
|
||||||
boolean netgame; // Start the game in an actual server
|
boolean netgame; // Start the game in an actual server
|
||||||
} levellist;
|
} levellist;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,9 @@ menuitem_t PLAY_GamemodesMenu[] =
|
||||||
{IT_STRING | IT_CALL, "Capsules", "Bust up all of the capsules in record time!",
|
{IT_STRING | IT_CALL, "Capsules", "Bust up all of the capsules in record time!",
|
||||||
NULL, {.routine = M_LevelSelectInit}, 1, GT_BATTLE},
|
NULL, {.routine = M_LevelSelectInit}, 1, GT_BATTLE},
|
||||||
|
|
||||||
|
{IT_STRING | IT_CALL, "Special", "Strike your target and secure the prize!",
|
||||||
|
NULL, {.routine = M_LevelSelectInit}, 1, GT_SPECIAL},
|
||||||
|
|
||||||
{IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0},
|
{IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1933,7 +1933,7 @@ static void M_DrawCupPreview(INT16 y, levelsearch_t *levelsearch)
|
||||||
|
|
||||||
V_DrawFill(0, y, BASEVIDWIDTH, 54, 31);
|
V_DrawFill(0, y, BASEVIDWIDTH, 54, 31);
|
||||||
|
|
||||||
if (levelsearch->cup && !M_CupLocked(levelsearch->cup))
|
if (levelsearch->cup && !M_CupLocked(levelsearch->cup) && maxlevels > 0)
|
||||||
{
|
{
|
||||||
add = (cupgrid.previewanim / 82) % maxlevels;
|
add = (cupgrid.previewanim / 82) % maxlevels;
|
||||||
map = start;
|
map = start;
|
||||||
|
|
@ -2002,7 +2002,10 @@ static void M_DrawCupTitle(INT16 y, cupheader_t *cup)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (currentMenu == &PLAY_LevelSelectDef)
|
if (currentMenu == &PLAY_LevelSelectDef)
|
||||||
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, y+6, 0, va("%s Mode", gametypes[levellist.newgametype]->name));
|
{
|
||||||
|
UINT8 namedgt = (levellist.guessgt != MAXGAMETYPES) ? levellist.guessgt : levellist.newgametype;
|
||||||
|
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, y+6, 0, va("%s Mode", gametypes[namedgt]->name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2261,7 +2264,8 @@ void M_DrawTimeAttack(void)
|
||||||
laprec = mapheaderinfo[map]->mainrecord->lap;
|
laprec = mapheaderinfo[map]->mainrecord->lap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
|
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
|
||||||
|
&& (mapheaderinfo[map]->numlaps != 1))
|
||||||
{
|
{
|
||||||
V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:");
|
V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:");
|
||||||
K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2);
|
K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2);
|
||||||
|
|
|
||||||
247
src/k_menufunc.c
247
src/k_menufunc.c
|
|
@ -3295,25 +3295,40 @@ void M_SetupGametypeMenu(INT32 choice)
|
||||||
|
|
||||||
PLAY_GamemodesDef.prevMenu = currentMenu;
|
PLAY_GamemodesDef.prevMenu = currentMenu;
|
||||||
|
|
||||||
// Battle and Capsules disabled
|
// Battle and Capsules (and Special) disabled
|
||||||
PLAY_GamemodesMenu[1].status = IT_DISABLED;
|
PLAY_GamemodesMenu[1].status = IT_DISABLED;
|
||||||
PLAY_GamemodesMenu[2].status = IT_DISABLED;
|
PLAY_GamemodesMenu[2].status = IT_DISABLED;
|
||||||
|
PLAY_GamemodesMenu[3].status = IT_DISABLED;
|
||||||
|
|
||||||
if (cv_splitplayers.value > 1)
|
if (cv_splitplayers.value > 1)
|
||||||
{
|
{
|
||||||
// Re-add Battle
|
// Re-add Battle
|
||||||
PLAY_GamemodesMenu[1].status = IT_STRING | IT_CALL;
|
PLAY_GamemodesMenu[1].status = IT_STRING | IT_CALL;
|
||||||
}
|
}
|
||||||
else if (M_SecretUnlocked(SECRET_BREAKTHECAPSULES, true))
|
|
||||||
{
|
|
||||||
// Re-add Capsules
|
|
||||||
PLAY_GamemodesMenu[2].status = IT_STRING | IT_CALL;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only one non-Back entry, let's skip straight to Race.
|
boolean anyunlocked = false;
|
||||||
M_SetupRaceMenu(-1);
|
|
||||||
return;
|
if (M_SecretUnlocked(SECRET_BREAKTHECAPSULES, true))
|
||||||
|
{
|
||||||
|
// Re-add Capsules
|
||||||
|
PLAY_GamemodesMenu[2].status = IT_STRING | IT_CALL;
|
||||||
|
anyunlocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (M_SecretUnlocked(SECRET_SPECIALATTACK, true))
|
||||||
|
{
|
||||||
|
// Re-add Special
|
||||||
|
PLAY_GamemodesMenu[3].status = IT_STRING | IT_CALL;
|
||||||
|
anyunlocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anyunlocked)
|
||||||
|
{
|
||||||
|
// Only one non-Back entry, let's skip straight to Race.
|
||||||
|
M_SetupRaceMenu(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
M_SetupNextMenu(&PLAY_GamemodesDef, false);
|
M_SetupNextMenu(&PLAY_GamemodesDef, false);
|
||||||
|
|
@ -3533,12 +3548,25 @@ static void M_LevelSelectScrollDest(void)
|
||||||
static void M_LevelListFromGametype(INT16 gt)
|
static void M_LevelListFromGametype(INT16 gt)
|
||||||
{
|
{
|
||||||
static boolean first = true;
|
static boolean first = true;
|
||||||
if (first || gt != levellist.newgametype)
|
if (first || gt != levellist.newgametype || levellist.guessgt != MAXGAMETYPES)
|
||||||
{
|
{
|
||||||
levellist.newgametype = gt;
|
levellist.newgametype = gt;
|
||||||
|
|
||||||
levellist.levelsearch.typeoflevel = G_TOLFlag(gt);
|
levellist.levelsearch.typeoflevel = G_TOLFlag(gt);
|
||||||
|
if (levellist.levelsearch.timeattack == true && gt == GT_SPECIAL)
|
||||||
|
{
|
||||||
|
// Sneak in an extra.
|
||||||
|
levellist.levelsearch.typeoflevel |= G_TOLFlag(GT_VERSUS);
|
||||||
|
levellist.guessgt = gt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
levellist.guessgt = MAXGAMETYPES;
|
||||||
|
}
|
||||||
|
|
||||||
levellist.levelsearch.cupmode = (!(gametypes[gt]->rules & GTR_NOCUPSELECT));
|
levellist.levelsearch.cupmode = (!(gametypes[gt]->rules & GTR_NOCUPSELECT));
|
||||||
levellist.levelsearch.cup = NULL;
|
levellist.levelsearch.cup = NULL;
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3680,6 +3708,100 @@ void M_LevelSelectInit(INT32 choice)
|
||||||
M_LevelListFromGametype(currentMenu->menuitems[itemOn].mvar2);
|
M_LevelListFromGametype(currentMenu->menuitems[itemOn].mvar2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void M_LevelSelected(INT16 add)
|
||||||
|
{
|
||||||
|
UINT8 i = 0;
|
||||||
|
INT16 map = M_GetFirstLevelInList(&i, &levellist.levelsearch);
|
||||||
|
|
||||||
|
while (add > 0)
|
||||||
|
{
|
||||||
|
map = M_GetNextLevelInList(map, &i, &levellist.levelsearch);
|
||||||
|
|
||||||
|
if (map >= nummapheaders)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
add--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map >= nummapheaders)
|
||||||
|
{
|
||||||
|
// This shouldn't happen
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
levellist.choosemap = map;
|
||||||
|
|
||||||
|
if (levellist.levelsearch.timeattack)
|
||||||
|
{
|
||||||
|
S_StartSound(NULL, sfx_s3k63);
|
||||||
|
|
||||||
|
if (levellist.guessgt != MAXGAMETYPES)
|
||||||
|
levellist.newgametype = G_GuessGametypeByTOL(levellist.levelsearch.typeoflevel);
|
||||||
|
|
||||||
|
PLAY_TimeAttackDef.prevMenu = currentMenu;
|
||||||
|
M_SetupNextMenu(&PLAY_TimeAttackDef, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (gamestate == GS_MENU)
|
||||||
|
{
|
||||||
|
UINT8 ssplayers = cv_splitplayers.value-1;
|
||||||
|
|
||||||
|
netgame = false;
|
||||||
|
multiplayer = true;
|
||||||
|
|
||||||
|
strncpy(connectedservername, cv_servername.string, MAXSERVERNAME);
|
||||||
|
|
||||||
|
// Still need to reset devmode
|
||||||
|
cht_debug = 0;
|
||||||
|
|
||||||
|
if (demo.playback)
|
||||||
|
G_StopDemo();
|
||||||
|
if (metalrecording)
|
||||||
|
G_StopMetalDemo();
|
||||||
|
|
||||||
|
/*if (levellist.choosemap == 0)
|
||||||
|
levellist.choosemap = G_RandMap(G_TOLFlag(levellist.newgametype), -1, 0, 0, false, NULL);*/
|
||||||
|
|
||||||
|
if (cv_maxconnections.value < ssplayers+1)
|
||||||
|
CV_SetValue(&cv_maxconnections, ssplayers+1);
|
||||||
|
|
||||||
|
if (splitscreen != ssplayers)
|
||||||
|
{
|
||||||
|
splitscreen = ssplayers;
|
||||||
|
SplitScreen_OnChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
S_StartSound(NULL, sfx_s3k63);
|
||||||
|
|
||||||
|
paused = false;
|
||||||
|
|
||||||
|
// Early fadeout to let the sound finish playing
|
||||||
|
F_WipeStartScreen();
|
||||||
|
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
||||||
|
F_WipeEndScreen();
|
||||||
|
F_RunWipe(wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
|
||||||
|
|
||||||
|
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
|
||||||
|
|
||||||
|
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string);
|
||||||
|
CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto");
|
||||||
|
CV_StealthSet(&cv_kartspeed, (cv_dummykartspeed.value == KARTSPEED_NORMAL) ? "Auto" : cv_dummykartspeed.string);
|
||||||
|
|
||||||
|
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// directly do the map change
|
||||||
|
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
M_ClearMenus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void M_CupSelectHandler(INT32 choice)
|
void M_CupSelectHandler(INT32 choice)
|
||||||
{
|
{
|
||||||
const UINT8 pid = 0;
|
const UINT8 pid = 0;
|
||||||
|
|
@ -3733,13 +3855,18 @@ void M_CupSelectHandler(INT32 choice)
|
||||||
|
|
||||||
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
|
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
|
||||||
{
|
{
|
||||||
|
INT16 count;
|
||||||
cupheader_t *newcup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
cupheader_t *newcup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||||
|
cupheader_t *oldcup = levellist.levelsearch.cup;
|
||||||
|
|
||||||
M_SetMenuDelay(pid);
|
M_SetMenuDelay(pid);
|
||||||
|
|
||||||
|
levellist.levelsearch.cup = newcup;
|
||||||
|
count = M_CountLevelsToShowInList(&levellist.levelsearch);
|
||||||
|
|
||||||
if ((!newcup)
|
if ((!newcup)
|
||||||
|| (M_CupLocked(newcup))
|
|| (count <= 0)
|
||||||
|| (newcup->cachedlevels[0] == NEXTMAP_INVALID))
|
|| (cupgrid.grandprix == true && newcup->cachedlevels[0] == NEXTMAP_INVALID))
|
||||||
{
|
{
|
||||||
S_StartSound(NULL, sfx_s3kb2);
|
S_StartSound(NULL, sfx_s3kb2);
|
||||||
return;
|
return;
|
||||||
|
|
@ -3803,13 +3930,17 @@ void M_CupSelectHandler(INT32 choice)
|
||||||
|
|
||||||
M_ClearMenus(true);
|
M_ClearMenus(true);
|
||||||
}
|
}
|
||||||
|
else if (count == 1)
|
||||||
|
{
|
||||||
|
PLAY_TimeAttackDef.transitionID = currentMenu->transitionID+1;
|
||||||
|
M_LevelSelected(0);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Keep cursor position if you select the same cup again, reset if it's a different cup
|
// Keep cursor position if you select the same cup again, reset if it's a different cup
|
||||||
if (levellist.levelsearch.cup != newcup)
|
if (oldcup != newcup || levellist.cursor >= count)
|
||||||
{
|
{
|
||||||
levellist.cursor = 0;
|
levellist.cursor = 0;
|
||||||
levellist.levelsearch.cup = newcup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
M_LevelSelectScrollDest();
|
M_LevelSelectScrollDest();
|
||||||
|
|
@ -3868,94 +3999,10 @@ void M_LevelSelectHandler(INT32 choice)
|
||||||
|
|
||||||
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
|
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
|
||||||
{
|
{
|
||||||
UINT8 i = 0;
|
|
||||||
INT16 map = M_GetFirstLevelInList(&i, &levellist.levelsearch);
|
|
||||||
INT16 add = levellist.cursor;
|
|
||||||
|
|
||||||
M_SetMenuDelay(pid);
|
M_SetMenuDelay(pid);
|
||||||
|
|
||||||
while (add > 0)
|
PLAY_TimeAttackDef.transitionID = currentMenu->transitionID;
|
||||||
{
|
M_LevelSelected(levellist.cursor);
|
||||||
map = M_GetNextLevelInList(map, &i, &levellist.levelsearch);
|
|
||||||
|
|
||||||
if (map >= nummapheaders)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
add--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map >= nummapheaders)
|
|
||||||
{
|
|
||||||
// This shouldn't happen
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
levellist.choosemap = map;
|
|
||||||
|
|
||||||
if (levellist.levelsearch.timeattack)
|
|
||||||
{
|
|
||||||
M_SetupNextMenu(&PLAY_TimeAttackDef, false);
|
|
||||||
S_StartSound(NULL, sfx_s3k63);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (gamestate == GS_MENU)
|
|
||||||
{
|
|
||||||
UINT8 ssplayers = cv_splitplayers.value-1;
|
|
||||||
|
|
||||||
netgame = false;
|
|
||||||
multiplayer = true;
|
|
||||||
|
|
||||||
strncpy(connectedservername, cv_servername.string, MAXSERVERNAME);
|
|
||||||
|
|
||||||
// Still need to reset devmode
|
|
||||||
cht_debug = 0;
|
|
||||||
|
|
||||||
if (demo.playback)
|
|
||||||
G_StopDemo();
|
|
||||||
if (metalrecording)
|
|
||||||
G_StopMetalDemo();
|
|
||||||
|
|
||||||
/*if (levellist.choosemap == 0)
|
|
||||||
levellist.choosemap = G_RandMap(G_TOLFlag(levellist.newgametype), -1, 0, 0, false, NULL);*/
|
|
||||||
|
|
||||||
if (cv_maxconnections.value < ssplayers+1)
|
|
||||||
CV_SetValue(&cv_maxconnections, ssplayers+1);
|
|
||||||
|
|
||||||
if (splitscreen != ssplayers)
|
|
||||||
{
|
|
||||||
splitscreen = ssplayers;
|
|
||||||
SplitScreen_OnChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
S_StartSound(NULL, sfx_s3k63);
|
|
||||||
|
|
||||||
paused = false;
|
|
||||||
|
|
||||||
// Early fadeout to let the sound finish playing
|
|
||||||
F_WipeStartScreen();
|
|
||||||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
|
||||||
F_WipeEndScreen();
|
|
||||||
F_RunWipe(wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
|
|
||||||
|
|
||||||
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
|
|
||||||
|
|
||||||
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string);
|
|
||||||
CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto");
|
|
||||||
CV_StealthSet(&cv_kartspeed, (cv_dummykartspeed.value == KARTSPEED_NORMAL) ? "Auto" : cv_dummykartspeed.string);
|
|
||||||
|
|
||||||
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// directly do the map change
|
|
||||||
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
M_ClearMenus(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (M_MenuBackPressed(pid))
|
else if (M_MenuBackPressed(pid))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,8 @@ typedef enum
|
||||||
|
|
||||||
// Menu restrictions
|
// Menu restrictions
|
||||||
SECRET_TIMEATTACK, // Permit Time attack
|
SECRET_TIMEATTACK, // Permit Time attack
|
||||||
SECRET_BREAKTHECAPSULES, // Permit SP Capsules
|
SECRET_BREAKTHECAPSULES, // Permit SP Capsule attack
|
||||||
|
SECRET_SPECIALATTACK, // Permit Special attack (You're blue now!)
|
||||||
SECRET_SOUNDTEST, // Permit Sound Test
|
SECRET_SOUNDTEST, // Permit Sound Test
|
||||||
SECRET_ALTTITLE, // Permit alternate titlescreen
|
SECRET_ALTTITLE, // Permit alternate titlescreen
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue