diff --git a/src/g_game.c b/src/g_game.c index 77d50b291..90ccf29c1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2151,7 +2151,7 @@ boolean G_Responder(event_t *ev) if (! netgame) F_StartGameEvaluation(); else if (server || IsPlayerAdmin(consoleplayer)) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); return true; } } @@ -4000,14 +4000,137 @@ static void G_HandleSaveLevel(void) } } +// +// G_GetNextMap +// +INT16 G_GetNextMap(boolean ignoretokens, boolean silent) +{ + INT32 i; + INT16 newmapnum; + boolean spec = G_IsSpecialStage(gamemap); + + // go to next level + // newmapnum is 0-based, unlike gamemap + if (nextmapoverride != 0) + newmapnum = (INT16)(nextmapoverride-1); + else if (marathonmode && mapheaderinfo[gamemap-1]->marathonnext) + newmapnum = (INT16)(mapheaderinfo[gamemap-1]->marathonnext-1); + else + { + newmapnum = (INT16)(mapheaderinfo[gamemap-1]->nextlevel-1); + if (marathonmode && newmapnum == spmarathon_start-1) + newmapnum = 1100-1; // No infinite loop for you + } + + INT16 gametype_to_use; + + if (nextgametype >= 0 && nextgametype < gametypecount) + gametype_to_use = nextgametype; + else + gametype_to_use = gametype; + + // If newmapnum is actually going to get used, make sure it points to + // a map of the proper gametype -- skip levels that don't support + // the current gametype. (Helps avoid playing boss levels in Race, + // for instance). + if (!spec || nextmapoverride) + { + if (newmapnum >= 0 && newmapnum < NUMMAPS) + { + INT16 cm = newmapnum; + UINT32 tolflag = G_TOLFlag(gametype_to_use); + UINT8 visitedmap[(NUMMAPS+7)/8]; + + memset(visitedmap, 0, sizeof (visitedmap)); + + while (!mapheaderinfo[cm] || !(mapheaderinfo[cm]->typeoflevel & tolflag)) + { + visitedmap[cm/8] |= (1<<(cm&7)); + if (!mapheaderinfo[cm]) + cm = -1; // guarantee error execution + else if (marathonmode && mapheaderinfo[cm]->marathonnext) + cm = (INT16)(mapheaderinfo[cm]->marathonnext-1); + else + cm = (INT16)(mapheaderinfo[cm]->nextlevel-1); + + if (cm >= NUMMAPS || cm < 0) // out of range (either 1100ish or error) + { + cm = newmapnum; //Start the loop again so that the error checking below is executed. + + //Make sure the map actually exists before you try to go to it! + if ((W_CheckNumForName(G_BuildMapName(cm + 1)) == LUMPERROR)) + { + if (!silent) + CONS_Alert(CONS_ERROR, M_GetText("Next map given (MAP %d) doesn't exist! Reverting to MAP01.\n"), cm+1); + cm = 0; + break; + } + } + + if (visitedmap[cm/8] & (1<<(cm&7))) // smells familiar + { + // We got stuck in a loop, came back to the map we started on + // without finding one supporting the current gametype. + // Thus, print a warning, and just use this map anyways. + if (!silent) + CONS_Alert(CONS_WARNING, M_GetText("Can't find a compatible map after map %d; using map %d anyway\n"), prevmap+1, cm+1); + break; + } + } + newmapnum = cm; + } + + // wrap around in race + if (newmapnum >= 1100-1 && newmapnum <= 1102-1 && !(gametyperules & GTR_CAMPAIGN)) + newmapnum = (INT16)(spstage_start-1); + + if (newmapnum < 0 || (newmapnum >= NUMMAPS && newmapnum < 1100-1) || newmapnum > 1103-1) + I_Error("Followed map %d to invalid map %d\n", prevmap + 1, newmapnum + 1); + + if (!spec) + lastmap = newmapnum; // Remember last map for when you come out of the special stage. + } + + if (!ignoretokens && (gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token))) + { + token--; + +// if (!nextmapoverride) // Having a token should pull the player into the special stage before going to the overridden map (Issue #933) + for (i = 0; i < 7; i++) + if (!(emeralds & (1<marathonnext) - nextmap = (INT16)(mapheaderinfo[gamemap-1]->marathonnext-1); - else - { - nextmap = (INT16)(mapheaderinfo[gamemap-1]->nextlevel-1); - if (marathonmode && nextmap == spmarathon_start-1) - nextmap = 1100-1; // No infinite loop for you - } - - INT16 gametype_to_use; - - if (nextgametype >= 0 && nextgametype < gametypecount) - gametype_to_use = nextgametype; - else - gametype_to_use = gametype; - - // If nextmap is actually going to get used, make sure it points to - // a map of the proper gametype -- skip levels that don't support - // the current gametype. (Helps avoid playing boss levels in Race, - // for instance). - if (!spec || nextmapoverride) - { - if (nextmap >= 0 && nextmap < NUMMAPS) - { - INT16 cm = nextmap; - UINT32 tolflag = G_TOLFlag(gametype_to_use); - UINT8 visitedmap[(NUMMAPS+7)/8]; - - memset(visitedmap, 0, sizeof (visitedmap)); - - while (!mapheaderinfo[cm] || !(mapheaderinfo[cm]->typeoflevel & tolflag)) - { - visitedmap[cm/8] |= (1<<(cm&7)); - if (!mapheaderinfo[cm]) - cm = -1; // guarantee error execution - else if (marathonmode && mapheaderinfo[cm]->marathonnext) - cm = (INT16)(mapheaderinfo[cm]->marathonnext-1); - else - cm = (INT16)(mapheaderinfo[cm]->nextlevel-1); - - if (cm >= NUMMAPS || cm < 0) // out of range (either 1100ish or error) - { - cm = nextmap; //Start the loop again so that the error checking below is executed. - - //Make sure the map actually exists before you try to go to it! - if ((W_CheckNumForName(G_BuildMapName(cm + 1)) == LUMPERROR)) - { - CONS_Alert(CONS_ERROR, M_GetText("Next map given (MAP %d) doesn't exist! Reverting to MAP01.\n"), cm+1); - cm = 0; - break; - } - } - - if (visitedmap[cm/8] & (1<<(cm&7))) // smells familiar - { - // We got stuck in a loop, came back to the map we started on - // without finding one supporting the current gametype. - // Thus, print a warning, and just use this map anyways. - CONS_Alert(CONS_WARNING, M_GetText("Can't find a compatible map after map %d; using map %d anyway\n"), prevmap+1, cm+1); - break; - } - } - nextmap = cm; - } - - // wrap around in race - if (nextmap >= 1100-1 && nextmap <= 1102-1 && !(gametyperules & GTR_CAMPAIGN)) - nextmap = (INT16)(spstage_start-1); - - if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1103-1) - I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); - - if (!spec) - lastmap = nextmap; // Remember last map for when you come out of the special stage. - } - - if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token))) - { - token--; - -// if (!nextmapoverride) // Having a token should pull the player into the special stage before going to the overridden map (Issue #933) - for (i = 0; i < 7; i++) - if (!(emeralds & (1< 30 * TICRATE) + continue; + if (players[i].lives <= 0) + continue; + + if ((players[i].pflags & PF_FINISHED) || players[i].exiting) + { + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + return; + } + } + } + + // Only consider it a cheat if we're not allowed to go to the next map + if (M_CampaignWarpIsCheat(gametype, G_GetNextMap(true, true) + 1, serverGamedata)) + CONS_Alert(CONS_NOTICE, M_GetText("Cheats must be enabled to force exit to a locked level!\n")); + else + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + } } static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) { - boolean cheat = false; - - cheat = (boolean)READUINT8(*cp); + (void)cp; // Ignore duplicate XD_EXITLEVEL commands. if (gameaction == ga_completed) - { return; - } if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -4535,11 +4560,6 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) return; } - if (G_CoopGametype() && cheat) - { - G_SetUsedCheats(false); - } - G_ExitLevel(); } diff --git a/src/netcode/d_netcmd.h b/src/netcode/d_netcmd.h index 0f2a1f92b..e30fa4a02 100644 --- a/src/netcode/d_netcmd.h +++ b/src/netcode/d_netcmd.h @@ -201,7 +201,6 @@ void D_SendPlayerConfig(void); void Command_ExitGame_f(void); void Command_Retry_f(void); void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore -void D_SendExitLevel(boolean cheat); void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect); boolean IsPlayerAdmin(INT32 playernum); void SetAdminPlayer(INT32 playernum); diff --git a/src/p_inter.c b/src/p_inter.c index 9a6f0ad06..d8765e7a2 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2244,7 +2244,7 @@ void P_CheckTimeLimit(void) } if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } //Optional tie-breaker for Match/CTF @@ -2307,11 +2307,11 @@ void P_CheckTimeLimit(void) } } if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } /** Checks if a player's score is over the pointlimit and the round should end. @@ -2340,7 +2340,7 @@ void P_CheckPointLimit(void) if ((UINT32)cv_pointlimit.value <= redscore || (UINT32)cv_pointlimit.value <= bluescore) { if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } } else @@ -2353,7 +2353,7 @@ void P_CheckPointLimit(void) if ((UINT32)cv_pointlimit.value <= players[i].score) { if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); return; } } @@ -2397,7 +2397,7 @@ void P_CheckSurvivors(void) { CONS_Printf(M_GetText("The IT player has left the game.\n")); if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); return; } @@ -2417,7 +2417,7 @@ void P_CheckSurvivors(void) { CONS_Printf(M_GetText("All players have been tagged!\n")); if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } return; @@ -2429,7 +2429,7 @@ void P_CheckSurvivors(void) { CONS_Printf(M_GetText("There are no players able to become IT.\n")); if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } return; @@ -2441,7 +2441,7 @@ void P_CheckSurvivors(void) { CONS_Printf(M_GetText("All players have been tagged!\n")); if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } } diff --git a/src/p_setup.c b/src/p_setup.c index d2126b0fc..9ae73c18b 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8315,7 +8315,7 @@ static boolean P_LoadAddon(UINT16 numlumps) { CONS_Printf(M_GetText("Current map %d replaced by added file, ending the level to ensure consistency.\n"), gamemap); if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } return true; diff --git a/src/p_user.c b/src/p_user.c index b9548ff3f..fe514f0bb 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -11904,7 +11904,7 @@ void P_PlayerThink(player_t *player) if (!total || ((4*exiting)/total) >= numneeded) { if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } else player->exiting = 3; @@ -11912,7 +11912,7 @@ void P_PlayerThink(player_t *player) else { if (server) - D_SendExitLevel(false); + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } }