diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index de5b2ea6c0439405f9099eb7373e1b3b4e6d1aa9..79d65054d96782310d34cbf688158577af4be686 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -2182,6 +2182,12 @@ linedeftypes prefix = "(461)"; flags64text = "[6] Spawn inside a range"; } + + 462 + { + title = "Stop timer/exit stage in Record Attack"; + prefix = "(462)"; + } } linedefexecmisc diff --git a/src/p_enemy.c b/src/p_enemy.c index cc2d64e8b9b7e6901a76bd3d520756cd9cdb3ea5..0d696437a7c23292cc2dc884a4f35d82838a4720 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3910,10 +3910,16 @@ void A_BossDeath(mobj_t *mo) // victory! P_LinedefExecute(LE_ALLBOSSESDEAD, mo, NULL); + if (stoppedclock && modeattacking) // if you're just time attacking, skip making the capsule appear since you don't need to step on it anyways. + goto bossjustdie; if (mo->flags2 & MF2_BOSSNOTRAP) { for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; P_DoPlayerExit(&players[i]); + } } else { @@ -10414,7 +10420,11 @@ void A_ForceWin(mobj_t *actor) return; for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; P_DoPlayerExit(&players[i]); + } } // Function: A_SpikeRetract diff --git a/src/p_mobj.h b/src/p_mobj.h index 94fcc29879727f110205e10656bcb97f45a81472..e560a4a815c8a2cb7230478ede484490de468728 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -475,4 +475,5 @@ extern boolean runemeraldmanager; extern UINT16 emeraldspawndelay; extern INT32 numstarposts; extern UINT16 bossdisabled; +extern boolean stoppedclock; #endif diff --git a/src/p_saveg.c b/src/p_saveg.c index fb2365bf0983e3de1cdb44b813ab9c333cc4bc48..470d3096ede6a7e01382d3d64515fb6a8fa1a982 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3981,7 +3981,6 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) static void P_NetArchiveMisc(void) { - UINT32 pig = 0; INT32 i; WRITEUINT32(save_p, ARCHIVEBLOCK_MISC); @@ -3989,9 +3988,12 @@ static void P_NetArchiveMisc(void) WRITEINT16(save_p, gamemap); WRITEINT16(save_p, gamestate); - for (i = 0; i < MAXPLAYERS; i++) - pig |= (playeringame[i] != 0)<<i; - WRITEUINT32(save_p, pig); + { + UINT32 pig = 0; + for (i = 0; i < MAXPLAYERS; i++) + pig |= (playeringame[i] != 0)<<i; + WRITEUINT32(save_p, pig); + } WRITEUINT32(save_p, P_GetRandSeed()); @@ -4003,7 +4005,14 @@ static void P_NetArchiveMisc(void) WRITEUINT16(save_p, bossdisabled); WRITEUINT16(save_p, emeralds); - WRITEUINT8(save_p, stagefailed); + { + UINT8 globools = 0; + if (stagefailed) + globools |= 1; + if (stoppedclock) + globools |= (1<<1); + WRITEUINT8(save_p, globools); + } WRITEUINT32(save_p, token); WRITEINT32(save_p, sstimer); @@ -4042,7 +4051,6 @@ static void P_NetArchiveMisc(void) static inline boolean P_NetUnArchiveMisc(void) { - UINT32 pig; INT32 i; if (READUINT32(save_p) != ARCHIVEBLOCK_MISC) @@ -4061,11 +4069,13 @@ static inline boolean P_NetUnArchiveMisc(void) G_SetGamestate(READINT16(save_p)); - pig = READUINT32(save_p); - for (i = 0; i < MAXPLAYERS; i++) { - playeringame[i] = (pig & (1<<i)) != 0; - // playerstate is set in unarchiveplayers + UINT32 pig = READUINT32(save_p); + for (i = 0; i < MAXPLAYERS; i++) + { + playeringame[i] = (pig & (1<<i)) != 0; + // playerstate is set in unarchiveplayers + } } P_SetRandSeed(READUINT32(save_p)); @@ -4082,7 +4092,11 @@ static inline boolean P_NetUnArchiveMisc(void) bossdisabled = READUINT16(save_p); emeralds = READUINT16(save_p); - stagefailed = READUINT8(save_p); + { + UINT8 globools = READUINT8(save_p); + stagefailed = !!(globools & 1); + stoppedclock = !!(globools & (1<<1)); + } token = READUINT32(save_p); sstimer = READINT32(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index cef17663635907eaa19feb77a40a33b22a636dc5..1e24189a613f1073d2f06f47f84aeb5acb872743 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -103,6 +103,7 @@ side_t *sides; mapthing_t *mapthings; INT32 numstarposts; UINT16 bossdisabled; +boolean stoppedclock; boolean levelloading; UINT8 levelfadecol; diff --git a/src/p_spec.c b/src/p_spec.c index 7b23ecbe7ae22794eb8961399ec76b8f9e9aaf28..bfa4c0eb7ed7d0072d1e892b7d62397727d75776 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3998,6 +3998,24 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; + case 462: // Stop clock (and end level in record attack) + if (G_PlatformGametype()) + { + stoppedclock = true; + CONS_Debug(DBG_GAMELOGIC, "Clock stopped!\n"); + if (modeattacking) + { + UINT8 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + P_DoPlayerExit(&players[i]); + } + } + } + break; + #ifdef POLYOBJECTS case 480: // Polyobj_DoorSlide case 481: // Polyobj_DoorSwing @@ -4513,7 +4531,11 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers // Mark all players with the time to exit thingy! for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; P_DoPlayerExit(&players[i]); + } break; } case 10: // Special Stage Time/Rings @@ -6387,6 +6409,7 @@ void P_SpawnSpecials(INT32 fromnetsave) // yep, we do this here - "bossdisabled" is considered an apparatus of specials. bossdisabled = 0; + stoppedclock = false; // Init special SECTORs. sector = sectors; diff --git a/src/p_tick.c b/src/p_tick.c index 6b5c7980c86d7307a460e66111b70d0bad37a23e..e02b11f4907fd5d87bb722467485b0409f66a28e 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -678,7 +678,7 @@ void P_Ticker(boolean run) if (run) { - if (countdowntimer && G_PlatformGametype() && (gametype == GT_COOP || leveltime >= 4*TICRATE) && --countdowntimer <= 0) + if (countdowntimer && G_PlatformGametype() && (gametype == GT_COOP || leveltime >= 4*TICRATE) && !stoppedclock && --countdowntimer <= 0) { countdowntimer = 0; countdowntimeup = true; diff --git a/src/p_user.c b/src/p_user.c index 561183cd5a7d0f6f3888e48897af8002bbac62e7..8b04596f3d80d4264497ef48e2802b2a45dcb89d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9377,7 +9377,7 @@ static void P_DeathThink(player_t *player) if (gametype == GT_RACE || gametype == GT_COMPETITION || (gametype == GT_COOP && (multiplayer || netgame))) { // Keep time rolling in race mode - if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_GAMETYPEOVER)) + if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_GAMETYPEOVER) && !stoppedclock) { if (gametype == GT_RACE || gametype == GT_COMPETITION) { @@ -11333,7 +11333,7 @@ void P_PlayerThink(player_t *player) } // Synchronizes the "real" amount of time spent in the level. - if (!player->exiting) + if (!player->exiting && !stoppedclock) { if (gametype == GT_RACE || gametype == GT_COMPETITION) { diff --git a/src/st_stuff.c b/src/st_stuff.c index 392cb1c03fe4d600a73f226a9d5eafd431ba4afa..737a1852f399424296943dad1d690f4b4f3eacea 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -707,7 +707,7 @@ static void ST_drawTime(void) { if (timelimitintics >= stplyr->realtime) { - tics = (timelimitintics - stplyr->realtime); + tics = (timelimitintics + (TICRATE-1) - stplyr->realtime); if (tics < 3*TICRATE) ST_drawRaceNum(tics); } @@ -740,10 +740,12 @@ static void ST_drawTime(void) if (F_GetPromptHideHud(hudinfo[HUD_TIME].y)) return; + downwards = (downwards && (tics < 30*TICRATE) && (leveltime/5 & 1) && !stoppedclock); // overtime? + // TIME: - ST_DrawPatchFromHud(HUD_TIME, ((downwards && (tics < 30*TICRATE) && (leveltime/5 & 1)) ? sboredtime : sbotime), V_HUDTRANS); + ST_DrawPatchFromHud(HUD_TIME, (downwards ? sboredtime : sbotime), V_HUDTRANS); - if (!tics && downwards && (leveltime/5 & 1)) // overtime! + if (downwards) // overtime! return; if (cv_timetic.value == 3) // Tics only -- how simple is this?