* Make exitlevel only work if someone's at the exit or you've visited the next map before.

* Added a message to suggest changing cheats before release to a future self.
* Removed the gametype selection menu, and baked its contents into the level platter instead (with an additional dose of pretty - https://cdn.discordapp.com/attachments/293238104096112641/359338275338584064/unknown.png)
This commit is contained in:
toasterbabe 2017-09-15 20:34:46 +01:00
parent 970268ec38
commit 918edda672
4 changed files with 164 additions and 135 deletions

View File

@ -3895,7 +3895,28 @@ static void Command_ExitLevel_f(void)
else if (gamestate != GS_LEVEL || demoplayback)
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
else
{
if ((netgame || multiplayer)
&& ((mapheaderinfo[gamemap-1]->nextlevel <= 0)
|| (mapheaderinfo[gamemap-1]->nextlevel > NUMMAPS)
|| !(mapvisited[mapheaderinfo[gamemap-1]->nextlevel-1])))
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].exiting)
break;
}
if (i == MAXPLAYERS)
{
CONS_Printf(M_GetText("Someone must finish the level for you to use this.\n"));
return;
}
}
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
}
static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)

View File

@ -131,6 +131,10 @@ static cheatseq_t cheat_ultimate_joy = {
SCRAMBLE(KEY_ENTER), 0xff }
};
#ifndef DEVELOP
Probably time to change these cheats?
#endif
static cheatseq_t cheat_warp = {
0, cheatf_warp,
{ SCRAMBLE('r'), SCRAMBLE('e'), SCRAMBLE('d'), SCRAMBLE('x'), SCRAMBLE('v'), SCRAMBLE('i'), 0xff }

View File

@ -254,7 +254,6 @@ static void M_Options(INT32 choice);
static void M_SelectableClearMenus(INT32 choice);
static void M_Retry(INT32 choice);
static void M_EndGame(INT32 choice);
static void M_GameTypeChange(INT32 choice);
static void M_MapChange(INT32 choice);
static void M_ChangeLevel(INT32 choice);
static void M_ConfirmSpectate(INT32 choice);
@ -352,7 +351,6 @@ static void M_DrawSkyRoom(void);
static void M_DrawChecklist(void);
static void M_DrawEmblemHints(void);
static void M_DrawPauseMenu(void);
static void M_DrawGameTypeMenu(void);
static void M_DrawServerMenu(void);
static void M_DrawLevelPlatterMenu(void);
static void M_DrawImageDef(void);
@ -545,7 +543,7 @@ static menuitem_t MPauseMenu[] =
{
{IT_STRING | IT_CALL, NULL, "Add-ons...", M_Addons, 8},
{IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16},
{IT_STRING | IT_CALL, NULL, "Switch Gametype/Level...", M_GameTypeChange, 24},
{IT_STRING | IT_CALL, NULL, "Switch Gametype/Level...", M_MapChange, 24},
{IT_STRING | IT_CALL, NULL, "Continue", M_SelectableClearMenus,40},
{IT_STRING | IT_CALL, NULL, "Player 1 Setup", M_SetupMultiPlayer, 48}, // splitscreen
@ -628,32 +626,16 @@ static menuitem_t MISC_ChangeTeamMenu[] =
{IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmTeamChange, 90},
};
static menuitem_t MISC_ChangeGameTypeMenu[] =
{
{IT_STRING|IT_CALL, NULL, "Co-op", M_MapChange, 0},
{IT_STRING|IT_CALL, NULL, "Competition", M_MapChange, 12},
{IT_STRING|IT_CALL, NULL, "Race", M_MapChange, 20},
{IT_STRING|IT_CALL, NULL, "Match", M_MapChange, 32},
{IT_STRING|IT_CALL, NULL, "Team Match", M_MapChange, 40},
{IT_STRING|IT_CALL, NULL, "Tag", M_MapChange, 52},
{IT_STRING|IT_CALL, NULL, "Hide & Seek", M_MapChange, 60},
{IT_STRING|IT_CALL, NULL, "Capture the Flag", M_MapChange, 72},
};
static const gtdesc_t gametypedesc[] =
{
{"Play through the single-player campaign with your friends, teaming up to beat Dr Eggman's nefarious challenges!"},
{"Speed your way through the main acts, competing in several different categories to see who's the best."},
{"There's not much to it - zoom through the level faster than everyone else."},
{"Sling rings at your foes in a free-for-all battle. Use the special weapon rings to your advantage!"},
{"Sling rings at your foes in a color-coded battle. Use the special weapon rings to your advantage!"},
{"Whoever's IT has to hunt down everyone else. If you get caught, you have to turn on your former friends!"},
{"Try and find a good hiding place in these maps - we dare you."},
{"Steal the flag from the enemy's base and bring it back to your own, but watch out - they could just as easily steal yours!"},
{{ 54, 54}, "Play through the single-player campaign with your friends, teaming up to beat Dr Eggman's nefarious challenges!"},
{{103, 103}, "Speed your way through the main acts, competing in several different categories to see who's the best."},
{{190, 190}, "There's not much to it - zoom through the level faster than everyone else."},
{{ 66, 66}, "Sling rings at your foes in a free-for-all battle. Use the special weapon rings to your advantage!"},
{{153, 37}, "Sling rings at your foes in a color-coded battle. Use the special weapon rings to your advantage!"},
{{123, 123}, "Whoever's IT has to hunt down everyone else. If you get caught, you have to turn on your former friends!"},
{{135, 135}, "Try and find a good hiding place in these maps - we dare you."},
{{ 37, 153}, "Steal the flag from the enemy's base and bring it back to your own, but watch out - they could just as easily steal yours!"},
};
static menuitem_t MISC_ChangeLevelMenu[] =
@ -930,7 +912,7 @@ static menuitem_t SP_PlayerMenu[] =
// Separated splitscreen and normal servers.
static menuitem_t MP_SplitServerMenu[] =
{
{IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_GameTypeChange, 100},
{IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100},
#ifdef NONET // In order to keep player setup accessible.
{IT_STRING|IT_CALL, NULL, "Player 1 setup...", M_SetupMultiPlayer, 110},
{IT_STRING|IT_CALL, NULL, "Player 2 setup...", M_SetupMultiPlayer2, 120},
@ -960,7 +942,7 @@ static menuitem_t MP_ServerMenu[] =
{IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Server Name", &cv_servername, 20},
{IT_STRING|IT_CVAR, NULL, "Max Players", &cv_maxplayers, 46},
{IT_STRING|IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 56},
{IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_GameTypeChange, 100},
{IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100},
{IT_STRING|IT_CALL, NULL, "More Options...", M_ServerOptions, 130},
{IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140},
};
@ -1507,22 +1489,11 @@ menu_t MISC_ScrambleTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ScrambleTeamMenu, &MPa
menu_t MISC_ChangeTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeTeamMenu, &MPauseDef, 27, 40);
// MP Gametype and map change menu
menu_t MISC_ChangeGameTypeDef =
{
NULL,
sizeof (MISC_ChangeGameTypeMenu)/sizeof (menuitem_t),
&MainDef, // Doesn't matter.
MISC_ChangeGameTypeMenu,
M_DrawGameTypeMenu,
30, (200 - (72+8))/2, // vertically centering
0,
NULL
};
menu_t MISC_ChangeLevelDef =
{
NULL,
sizeof (MISC_ChangeLevelMenu)/sizeof (menuitem_t),
&MISC_ChangeGameTypeDef,
&MainDef, // Doesn't matter.
MISC_ChangeLevelMenu,
M_DrawLevelPlatterMenu,
0, 0,
@ -2538,21 +2509,11 @@ boolean M_Responder(event_t *ev)
case KEY_DOWNARROW:
M_NextOpt();
S_StartSound(NULL, sfx_menu1);
if (currentMenu == &MISC_ChangeGameTypeDef)
{
Z_Free(char_notes);
char_notes = NULL;
}
return true;
case KEY_UPARROW:
M_PrevOpt();
S_StartSound(NULL, sfx_menu1);
if (currentMenu == &MISC_ChangeGameTypeDef)
{
Z_Free(char_notes);
char_notes = NULL;
}
return true;
case KEY_LEFTARROW:
@ -3981,6 +3942,9 @@ static INT32 M_CountRowsToShowOnPlatter(INT32 gt)
mapnum++;
}
if (levellistmode == LLM_CREATESERVER)
rows++;
return rows;
}
@ -3990,10 +3954,10 @@ static INT32 M_CountRowsToShowOnPlatter(INT32 gt)
// Prepares a tasty dish of zones and acts!
// Call before any attempt to access a level platter.
//
static boolean M_PrepareLevelPlatter(INT32 gt)
static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick)
{
INT32 numrows = M_CountRowsToShowOnPlatter(gt);
INT32 mapnum = 0, prevmapnum = 0, col = 0, row = 0;
INT32 mapnum = 0, prevmapnum = 0, col = 0, row = 0, startrow = 0;
if (!numrows)
return false;
@ -4010,6 +3974,17 @@ static boolean M_PrepareLevelPlatter(INT32 gt)
// done here so lsrow and lscol can be set if cv_nextmap is on the platter
lsrow = lscol = lshli = lsoffs[0] = lsoffs[1] = 0;
if (levellistmode == LLM_CREATESERVER)
{
sprintf(levelselect.rows[0].header, "Gametype");
lswide(0) = true;
levelselect.rows[row].mapavailable[2] = levelselect.rows[row].mapavailable[1] = levelselect.rows[row].mapavailable[0] = false;
startrow = row = 1;
Z_Free(char_notes);
char_notes = NULL;
}
while (mapnum < NUMMAPS)
{
if (M_CanShowLevelOnPlatter(mapnum, gt))
@ -4019,7 +3994,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt)
const boolean wide = (mapheaderinfo[mapnum]->menuflags & LF2_WIDEICON);
// preparing next position to drop mapnum into
if (levelselect.rows[0].maplist[0])
if (levelselect.rows[startrow].maplist[0])
{
if (col == 2 // no more space on the row?
|| wide
@ -4042,7 +4017,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt)
levelselect.rows[row].mapavailable[2] = levelselect.rows[row].mapavailable[1] = levelselect.rows[row].mapavailable[0];
}
if (cv_nextmap.value == mapnum+1) // A little quality of life improvement.
if (nextmappick && cv_nextmap.value == mapnum+1) // A little quality of life improvement.
{
lsrow = row;
lscol = col;
@ -4084,7 +4059,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt)
sprintf(levelselect.rows[row].mapnames[col], "???");
// creating header text
if (!col && (!row || !(fastcmp(mapheaderinfo[mapnum]->selectheading, mapheaderinfo[levelselect.rows[row-1].maplist[0]-1]->selectheading))))
if (!col && ((row == startrow) || !(fastcmp(mapheaderinfo[mapnum]->selectheading, mapheaderinfo[levelselect.rows[row-1].maplist[0]-1]->selectheading))))
{
if (!levelselect.rows[row].mapavailable[col])
sprintf(levelselect.rows[row].header, "???");
@ -4126,12 +4101,11 @@ static boolean M_PrepareLevelPlatter(INT32 gt)
return true;
}
#define selectvalnextmapnobrace(column) selectval = levelselect.rows[lsrow].maplist[column];\
if (selectval && levelselect.rows[lsrow].mapavailable[column])\
#define ifselectvalnextmapnobrace(column) if ((selectval = levelselect.rows[lsrow].maplist[column]) && levelselect.rows[lsrow].mapavailable[column])\
{\
CV_SetValue(&cv_nextmap, selectval);
#define selectvalnextmap(column) selectvalnextmapnobrace(column)}
#define ifselectvalnextmap(column) ifselectvalnextmapnobrace(column)}
//
// M_HandleLevelPlatter
@ -4158,7 +4132,7 @@ static void M_HandleLevelPlatter(INT32 choice)
S_StartSound(NULL,sfx_s3kb7);
selectvalnextmap(lscol) else selectvalnextmap(0)
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
break;
case KEY_UPARROW:
@ -4181,35 +4155,59 @@ static void M_HandleLevelPlatter(INT32 choice)
S_StartSound(NULL,sfx_s3kb7);
selectvalnextmap(lscol) else selectvalnextmap(0)
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
break;
case KEY_LEFTARROW:
if (lscol > 0)
case KEY_ENTER:
if (!(levellistmode == LLM_CREATESERVER && !lsrow))
{
lscol--;
lsoffs[1] = (lswide(lsrow) ? -8 : lshseperation);
S_StartSound(NULL,sfx_s3kb7);
selectvalnextmap(lscol) else selectvalnextmap(0)
ifselectvalnextmapnobrace(lscol)
lsoffs[0] = lsoffs[1] = 0;
S_StartSound(NULL,sfx_menu1);
if (gamestate == GS_TIMEATTACK)
M_SetupNextMenu(currentMenu->prevMenu);
else if (currentMenu == &MISC_ChangeLevelDef)
{
if (currentMenu->prevMenu && currentMenu->prevMenu != &MPauseDef)
M_SetupNextMenu(currentMenu->prevMenu);
else
M_ChangeLevel(0);
Z_Free(levelselect.rows);
levelselect.rows = NULL;
}
else
M_LevelSelectWarp(0);
Nextmap_OnChange();
}
else if (!lsoffs[0]) // prevent sound spam
{
lsoffs[0] = -8;
S_StartSound(NULL,sfx_s3kb2);
}
break;
}
else if (!lsoffs[1]) // prevent sound spam
{
lsoffs[1] = -8;
S_StartSound(NULL,sfx_s3kb7);
}
break;
// intentionall fallthrough
case KEY_RIGHTARROW:
if (lscol < 2)
if (levellistmode == LLM_CREATESERVER && !lsrow)
{
CV_AddValue(&cv_newgametype, 1);
S_StartSound(NULL,sfx_menu1);
lscol = 0;
Z_Free(char_notes);
char_notes = NULL;
if (!M_PrepareLevelPlatter(cv_newgametype.value, false))
I_Error("Unidentified level platter failure!");
}
else if (lscol < 2)
{
lscol++;
lsoffs[1] = (lswide(lsrow) ? 8 : -lshseperation);
S_StartSound(NULL,sfx_s3kb7);
selectvalnextmap(lscol) else selectvalnextmap(0)
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
}
else if (!lsoffs[1]) // prevent sound spam
{
@ -4218,30 +4216,32 @@ static void M_HandleLevelPlatter(INT32 choice)
}
break;
case KEY_ENTER:
selectvalnextmapnobrace(lscol)
lsoffs[0] = lsoffs[1] = 0;
S_StartSound(NULL,sfx_menu1);
if (gamestate == GS_TIMEATTACK)
M_SetupNextMenu(currentMenu->prevMenu);
else if (currentMenu == &MISC_ChangeLevelDef)
{
if (currentMenu->prevMenu && currentMenu->prevMenu->prevMenu != &MPauseDef)
M_SetupNextMenu(currentMenu->prevMenu->prevMenu);
else
M_ChangeLevel(0);
Z_Free(levelselect.rows);
levelselect.rows = NULL;
}
else
M_LevelSelectWarp(0);
Nextmap_OnChange();
}
else if (!lsoffs[0]) // prevent sound spam
case KEY_LEFTARROW:
if (levellistmode == LLM_CREATESERVER && !lsrow)
{
lsoffs[0] = -8;
S_StartSound(NULL,sfx_s3kb2);
CV_AddValue(&cv_newgametype, -1);
S_StartSound(NULL,sfx_menu1);
lscol = 0;
Z_Free(char_notes);
char_notes = NULL;
if (!M_PrepareLevelPlatter(cv_newgametype.value, false))
I_Error("Unidentified level platter failure!");
}
else if (lscol > 0)
{
lscol--;
lsoffs[1] = (lswide(lsrow) ? -8 : lshseperation);
S_StartSound(NULL,sfx_s3kb7);
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
}
else if (!lsoffs[1]) // prevent sound spam
{
lsoffs[1] = -8;
S_StartSound(NULL,sfx_s3kb7);
}
break;
@ -4262,8 +4262,12 @@ static void M_HandleLevelPlatter(INT32 choice)
}
else
M_ClearMenus(true);
Z_Free(levelselect.rows);
levelselect.rows = NULL;
Z_Free(char_notes);
char_notes = NULL;
}
}
@ -4377,7 +4381,28 @@ static void M_DrawLevelPlatterRow(UINT8 row, INT32 y)
y += lsheadingheight;
}
if (lswide(row))
if (levellistmode == LLM_CREATESERVER && !row)
{
if (!char_notes)
char_notes = V_WordWrap(0, 282 - 8, V_ALLOWLOWERCASE, gametypedesc[cv_newgametype.value].notes);
V_DrawFill(lsbasex, y, 282, 50, 27);
V_DrawString(lsbasex + 4, y + 4, V_RETURN8|V_ALLOWLOWERCASE, char_notes);
V_DrawFill(lsbasex, y+50, 141, 8, gametypedesc[cv_newgametype.value].col[0]);
V_DrawFill(lsbasex+141, y+50, 141, 8, gametypedesc[cv_newgametype.value].col[1]);
V_DrawString(lsbasex, y+50, 0, gametype_cons_t[cv_newgametype.value].strvalue);
if (!lsrow)
{
V_DrawCharacter(lsbasex - 10 - (skullAnimCounter/5), y+25,
'\x1C' | V_YELLOWMAP, false);
V_DrawCharacter(lsbasex+282 + 2 + (skullAnimCounter/5), y+25,
'\x1D' | V_YELLOWMAP, false);
}
}
else if (lswide(row))
M_DrawLevelPlatterWideMap(row, 0, lsbasex, y, rowhighlight);
else
{
@ -4411,10 +4436,13 @@ static void M_DrawLevelPlatterMenu(void)
}
// draw cursor box
V_DrawSmallScaledPatch(lsbasex + cursorx + lsoffs[1], lsbasey, 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)]));
if (levellistmode != LLM_CREATESERVER || lsrow)
V_DrawSmallScaledPatch(lsbasex + cursorx + lsoffs[1], lsbasey, 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)]));
#if 0
if (levelselect.rows[lsrow].maplist[lscol])
V_DrawScaledPatch(lsbasex + cursorx-17, lsbasey+50+lsoffs[0], 0, W_CachePatchName("M_CURSOR", PU_CACHE));
#endif
// handle movement of cursor box
if (abs(lsoffs[0]) > 1)
@ -6012,7 +6040,7 @@ static void M_CustomLevelSelect(INT32 choice)
levellistmode = LLM_LEVELSELECT;
maplistoption = (UINT8)(unlockables[ul].variable);
if (!M_PrepareLevelPlatter(-1))
if (!M_PrepareLevelPlatter(-1, true))
{
M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING);
return;
@ -6044,7 +6072,7 @@ static void M_LoadGameLevelSelect(INT32 choice)
levellistmode = LLM_LEVELSELECT;
maplistoption = 1;
if (!M_PrepareLevelPlatter(-1))
if (!M_PrepareLevelPlatter(-1, true))
{
M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING);
return;
@ -7181,7 +7209,7 @@ static void M_TimeAttack(INT32 choice)
SP_TimeAttackDef.prevMenu = &MainDef;
levellistmode = LLM_RECORDATTACK; // Don't be dependent on cv_newgametype
if (!M_PrepareLevelPlatter(-1))
if (!M_PrepareLevelPlatter(-1, true))
{
M_StartMessage(M_GetText("No record-attackable levels found.\n"),NULL,MM_NOTHING);
return;
@ -7358,7 +7386,7 @@ static void M_NightsAttack(INT32 choice)
SP_NightsAttackDef.prevMenu = &MainDef;
levellistmode = LLM_NIGHTSATTACK; // Don't be dependent on cv_newgametype
if (!M_PrepareLevelPlatter(-1))
if (!M_PrepareLevelPlatter(-1, true))
{
M_StartMessage(M_GetText("No NiGHTS-attackable levels found.\n"),NULL,MM_NOTHING);
return;
@ -8063,42 +8091,17 @@ static void M_DrawServerMenu(void)
}
}
static void M_GameTypeChange(INT32 choice)
static void M_MapChange(INT32 choice)
{
(void)choice;
MISC_ChangeGameTypeDef.prevMenu = currentMenu;
M_SetupNextMenu(&MISC_ChangeGameTypeDef);
if (Playing())
itemOn = gametype;
Z_Free(char_notes);
char_notes = NULL;
}
void M_DrawGameTypeMenu(void)
{
M_DrawGenericMenu();
M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight, "Select Gametype", true, false);
if (!char_notes)
char_notes = V_WordWrap(0, (160 - 30) - 8, V_ALLOWLOWERCASE, gametypedesc[itemOn].notes);
V_DrawFill(160, currentMenu->y, (160 - 30), 72 + 8, 159);
V_DrawString(164, currentMenu->y + 4, V_RETURN8|V_ALLOWLOWERCASE, char_notes);
}
static void M_MapChange(INT32 choice)
{
MISC_ChangeLevelDef.prevMenu = currentMenu;
levellistmode = LLM_CREATESERVER;
CV_SetValue(&cv_newgametype, choice);
if (Playing() && !(M_CanShowLevelOnPlatter(cv_nextmap.value-1, choice)) && (M_CanShowLevelOnPlatter(gamemap-1, choice)))
if (Playing() && !(M_CanShowLevelOnPlatter(cv_nextmap.value-1, cv_newgametype.value)) && (M_CanShowLevelOnPlatter(gamemap-1, cv_newgametype.value)))
CV_SetValue(&cv_nextmap, gamemap);
if (!M_PrepareLevelPlatter(choice))
if (!M_PrepareLevelPlatter(cv_newgametype.value, (currentMenu == &MPauseDef)))
{
M_StartMessage(M_GetText("No selectable levels found.\n"),NULL,MM_NOTHING);
return;

View File

@ -201,6 +201,7 @@ typedef struct
// descriptions for gametype select screen
typedef struct
{
UINT8 col[2];
char notes[441];
} gtdesc_t;