diff --git a/src/g_demo.cpp b/src/g_demo.cpp index 405163790..36fa470ea 100644 --- a/src/g_demo.cpp +++ b/src/g_demo.cpp @@ -3959,6 +3959,7 @@ void G_StopDemo(void) demobuf.buffer = NULL; demo.playback = false; demo.timing = false; + demo.waitingfortally = false; g_singletics = false; { @@ -3990,7 +3991,13 @@ boolean G_CheckDemoStatus(void) if (demo.quitafterplaying) I_Quit(); - if (multiplayer && !demo.attract) + // When this replay was recorded, the player skipped + // the Tally and ended the demo early. + // Keep the demo open and don't boot to intermission + // YET, pause demo playback. + if (!demo.waitingfortally && modeattacking && exitcountdown) + demo.waitingfortally = true; + else if (!demo.attract) G_FinishExitLevel(); else { @@ -4025,6 +4032,7 @@ boolean G_CheckDemoStatus(void) Z_Free(demobuf.buffer); demo.recording = false; + demo.waitingfortally = false; return false; } diff --git a/src/g_demo.h b/src/g_demo.h index 7a43d33c0..a7f99b241 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -90,6 +90,7 @@ struct demovars_s { boolean quitafterplaying; // quit after playing a demo from cmdline boolean deferstart; // don't start playing demo right away boolean netgame; // multiplayer netgame + boolean waitingfortally; // demo ended but we're keeping the level open for the tally to finish tic_t savebutton; // Used to determine when the local player can choose to save the replay while the race is still going boolean willsave; diff --git a/src/g_game.c b/src/g_game.c index 45f7ae9ba..c6d1f9539 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2003,7 +2003,7 @@ void G_Ticker(boolean run) memset(player_name_changes, 0, sizeof player_name_changes); } - if (Playing() == true) + if (Playing() == true || demo.playback) { if (musiccountdown > 1) { @@ -2017,7 +2017,10 @@ void G_Ticker(boolean run) P_EndingMusic(); } } + } + if (Playing() == true) + { P_InvincGrowMusic(); K_TickMidVote(); diff --git a/src/g_party.cpp b/src/g_party.cpp index 6f83841c0..c0e1844c0 100644 --- a/src/g_party.cpp +++ b/src/g_party.cpp @@ -101,7 +101,7 @@ public: bool local() const { // consoleplayer is not valid yet. - if (!addedtogame) + if (!addedtogame && !demo.playback) { return false; } diff --git a/src/k_tally.cpp b/src/k_tally.cpp index 53a0fbb7f..519428dcb 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -35,6 +35,7 @@ #include "st_stuff.h" #include "r_fps.h" #include "g_party.h" +#include "g_input.h" boolean level_tally_t::UseBonuses(void) { @@ -311,6 +312,7 @@ void level_tally_t::Init(player_t *player) laps = totalLaps = 0; points = pointLimit = 0; powerStones = 0; + releasedFastForward = false; rank = GRADE_INVALID; @@ -1392,7 +1394,42 @@ void K_InitPlayerTally(player_t *player) void K_TickPlayerTally(player_t *player) { - player->tally.Tick(); + boolean fastForwardInput = !demo.playback && P_IsMachineLocalPlayer(player) && + G_PlayerInputDown(G_LocalSplitscreenPartyPosition(player - players), gc_a, 0); + boolean allowFastForward = player->tally.state > TALLY_ST_GOTTHRU_SLIDEIN + && player->tally.state <= TALLY_ST_DONE + && player->tally.releasedFastForward + // - Not allowed online so we don't have to do any + // networking. + // - Not allowed in replays because splitscreen party + // doesn't exist and it's just simpler to not think + // about. + && (!netgame && !demo.playback) + && player->tally.state != TALLY_ST_DONE; + + if (fastForwardInput && allowFastForward) + { + do + player->tally.Tick(); + while (player->tally.state != TALLY_ST_DONE && player->tally.state != TALLY_ST_GAMEOVER_DONE); + + player->tally.delay = std::min(player->tally.delay, TICRATE); + musiccountdown = 2; // gets decremented to 1 in G_Ticker to immediately trigger intermission music [blows raspberry] + } + else + { + player->tally.Tick(); + } + + if (!fastForwardInput) + { + player->tally.releasedFastForward = true; + } + else + { + player->tally.releasedFastForward = false; + } + } void K_DrawPlayerTally(void) diff --git a/src/k_tally.h b/src/k_tally.h index 9f7c3d866..62587cd7b 100644 --- a/src/k_tally.h +++ b/src/k_tally.h @@ -96,6 +96,7 @@ struct level_tally_t UINT8 xtraBlink; boolean showGrade; boolean done; + boolean releasedFastForward; #ifdef __cplusplus boolean UseBonuses(void); diff --git a/src/p_tick.c b/src/p_tick.c index c797e70df..55d051709 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -904,7 +904,7 @@ void P_Ticker(boolean run) if (playeringame[i]) G_WriteDemoTiccmd(&players[i].cmd, i); } - if (demo.playback) + if (demo.playback && !demo.waitingfortally) { G_ReadDemoExtraData(); for (i = 0; i < MAXPLAYERS; i++) @@ -1150,9 +1150,12 @@ void P_Ticker(boolean run) exitcountdown--; } - if (server && exitcountdown == 1) + if (exitcountdown == 1) { - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + if (demo.playback) + G_FinishExitLevel(); + else if (server) + SendNetXCmd(XD_EXITLEVEL, NULL, 0); } } } @@ -1204,14 +1207,15 @@ void P_Ticker(boolean run) if (cv_recordmultiplayerdemos.value && demo.savebutton && demo.savebutton + 3*TICRATE < leveltime) G_CheckDemoTitleEntry(); } - else if (demo.playback) // Use Ghost data for consistency checks. + else if (demo.playback && !demo.waitingfortally) // Use Ghost data for consistency checks. { G_ConsAllGhostTics(); } if (modeattacking) { - G_GhostTicker(); + if (!demo.waitingfortally) + G_GhostTicker(); if (!demo.playback) G_TickTimeStickerMedals(); } diff --git a/src/p_user.c b/src/p_user.c index 02eaa62fd..d0830677d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1273,7 +1273,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags) K_UpdatePowerLevelsFinalize(player, false); - if (P_IsPartyPlayer(player) && !specialout && musiccountdown == 0) + if (G_IsPartyLocal(player - players) && !specialout && musiccountdown == 0) { Music_Play("finish_silence"); musiccountdown = MUSIC_COUNTDOWN_MAX; @@ -3844,7 +3844,7 @@ void P_DoTimeOver(player_t *player) P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER); } - if (P_IsPartyPlayer(player) && musiccountdown == 0) + if (G_IsPartyLocal(player - players) && musiccountdown == 0) { Music_Play("finish_silence"); musiccountdown = MUSIC_COUNTDOWN_MAX;