STOP THE CLOCK linedef exectutor!

* When activated, stops the timer in SP/MP.
* Applies to the mapheader countdowntimer as well.
* If you're playing Record Attack, also exits the level immediately.
* It has no special modes, no linedef flags, no parameters, nothing.
* Only not an innate property of A_BossDeath because people may want it to NOT happen sometimes, or make it happen with non-boss events too.

Also, skip over calling P_DoPlayerExit if the player isn't in game.
This commit is contained in:
toaster 2019-11-08 15:47:12 +00:00
parent b157c21a35
commit d8ad0b4eaa
9 changed files with 75 additions and 18 deletions

View file

@ -2182,6 +2182,12 @@ linedeftypes
prefix = "(461)"; prefix = "(461)";
flags64text = "[6] Spawn inside a range"; flags64text = "[6] Spawn inside a range";
} }
462
{
title = "Stop timer/exit stage in Record Attack";
prefix = "(462)";
}
} }
linedefexecmisc linedefexecmisc

View file

@ -3910,10 +3910,16 @@ void A_BossDeath(mobj_t *mo)
// victory! // victory!
P_LinedefExecute(LE_ALLBOSSESDEAD, mo, NULL); 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) if (mo->flags2 & MF2_BOSSNOTRAP)
{ {
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
P_DoPlayerExit(&players[i]); P_DoPlayerExit(&players[i]);
}
} }
else else
{ {
@ -10414,7 +10420,11 @@ void A_ForceWin(mobj_t *actor)
return; return;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
P_DoPlayerExit(&players[i]); P_DoPlayerExit(&players[i]);
}
} }
// Function: A_SpikeRetract // Function: A_SpikeRetract

View file

@ -475,4 +475,5 @@ extern boolean runemeraldmanager;
extern UINT16 emeraldspawndelay; extern UINT16 emeraldspawndelay;
extern INT32 numstarposts; extern INT32 numstarposts;
extern UINT16 bossdisabled; extern UINT16 bossdisabled;
extern boolean stoppedclock;
#endif #endif

View file

@ -3981,7 +3981,6 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride)
static void P_NetArchiveMisc(void) static void P_NetArchiveMisc(void)
{ {
UINT32 pig = 0;
INT32 i; INT32 i;
WRITEUINT32(save_p, ARCHIVEBLOCK_MISC); WRITEUINT32(save_p, ARCHIVEBLOCK_MISC);
@ -3989,9 +3988,12 @@ static void P_NetArchiveMisc(void)
WRITEINT16(save_p, gamemap); WRITEINT16(save_p, gamemap);
WRITEINT16(save_p, gamestate); WRITEINT16(save_p, gamestate);
for (i = 0; i < MAXPLAYERS; i++) {
pig |= (playeringame[i] != 0)<<i; UINT32 pig = 0;
WRITEUINT32(save_p, pig); for (i = 0; i < MAXPLAYERS; i++)
pig |= (playeringame[i] != 0)<<i;
WRITEUINT32(save_p, pig);
}
WRITEUINT32(save_p, P_GetRandSeed()); WRITEUINT32(save_p, P_GetRandSeed());
@ -4003,7 +4005,14 @@ static void P_NetArchiveMisc(void)
WRITEUINT16(save_p, bossdisabled); WRITEUINT16(save_p, bossdisabled);
WRITEUINT16(save_p, emeralds); 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); WRITEUINT32(save_p, token);
WRITEINT32(save_p, sstimer); WRITEINT32(save_p, sstimer);
@ -4042,7 +4051,6 @@ static void P_NetArchiveMisc(void)
static inline boolean P_NetUnArchiveMisc(void) static inline boolean P_NetUnArchiveMisc(void)
{ {
UINT32 pig;
INT32 i; INT32 i;
if (READUINT32(save_p) != ARCHIVEBLOCK_MISC) if (READUINT32(save_p) != ARCHIVEBLOCK_MISC)
@ -4061,11 +4069,13 @@ static inline boolean P_NetUnArchiveMisc(void)
G_SetGamestate(READINT16(save_p)); G_SetGamestate(READINT16(save_p));
pig = READUINT32(save_p);
for (i = 0; i < MAXPLAYERS; i++)
{ {
playeringame[i] = (pig & (1<<i)) != 0; UINT32 pig = READUINT32(save_p);
// playerstate is set in unarchiveplayers for (i = 0; i < MAXPLAYERS; i++)
{
playeringame[i] = (pig & (1<<i)) != 0;
// playerstate is set in unarchiveplayers
}
} }
P_SetRandSeed(READUINT32(save_p)); P_SetRandSeed(READUINT32(save_p));
@ -4082,7 +4092,11 @@ static inline boolean P_NetUnArchiveMisc(void)
bossdisabled = READUINT16(save_p); bossdisabled = READUINT16(save_p);
emeralds = 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); token = READUINT32(save_p);
sstimer = READINT32(save_p); sstimer = READINT32(save_p);

View file

@ -103,6 +103,7 @@ side_t *sides;
mapthing_t *mapthings; mapthing_t *mapthings;
INT32 numstarposts; INT32 numstarposts;
UINT16 bossdisabled; UINT16 bossdisabled;
boolean stoppedclock;
boolean levelloading; boolean levelloading;
UINT8 levelfadecol; UINT8 levelfadecol;

View file

@ -3998,6 +3998,24 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
} }
break; 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 #ifdef POLYOBJECTS
case 480: // Polyobj_DoorSlide case 480: // Polyobj_DoorSlide
case 481: // Polyobj_DoorSwing 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! // Mark all players with the time to exit thingy!
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
P_DoPlayerExit(&players[i]); P_DoPlayerExit(&players[i]);
}
break; break;
} }
case 10: // Special Stage Time/Rings 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. // yep, we do this here - "bossdisabled" is considered an apparatus of specials.
bossdisabled = 0; bossdisabled = 0;
stoppedclock = false;
// Init special SECTORs. // Init special SECTORs.
sector = sectors; sector = sectors;

View file

@ -678,7 +678,7 @@ void P_Ticker(boolean run)
if (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; countdowntimer = 0;
countdowntimeup = true; countdowntimeup = true;

View file

@ -9377,7 +9377,7 @@ static void P_DeathThink(player_t *player)
if (gametype == GT_RACE || gametype == GT_COMPETITION || (gametype == GT_COOP && (multiplayer || netgame))) if (gametype == GT_RACE || gametype == GT_COMPETITION || (gametype == GT_COOP && (multiplayer || netgame)))
{ {
// Keep time rolling in race mode // 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) 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. // Synchronizes the "real" amount of time spent in the level.
if (!player->exiting) if (!player->exiting && !stoppedclock)
{ {
if (gametype == GT_RACE || gametype == GT_COMPETITION) if (gametype == GT_RACE || gametype == GT_COMPETITION)
{ {

View file

@ -707,7 +707,7 @@ static void ST_drawTime(void)
{ {
if (timelimitintics >= stplyr->realtime) if (timelimitintics >= stplyr->realtime)
{ {
tics = (timelimitintics - stplyr->realtime); tics = (timelimitintics + (TICRATE-1) - stplyr->realtime);
if (tics < 3*TICRATE) if (tics < 3*TICRATE)
ST_drawRaceNum(tics); ST_drawRaceNum(tics);
} }
@ -740,10 +740,12 @@ static void ST_drawTime(void)
if (F_GetPromptHideHud(hudinfo[HUD_TIME].y)) if (F_GetPromptHideHud(hudinfo[HUD_TIME].y))
return; return;
// TIME: downwards = (downwards && (tics < 30*TICRATE) && (leveltime/5 & 1) && !stoppedclock); // overtime?
ST_DrawPatchFromHud(HUD_TIME, ((downwards && (tics < 30*TICRATE) && (leveltime/5 & 1)) ? sboredtime : sbotime), V_HUDTRANS);
if (!tics && downwards && (leveltime/5 & 1)) // overtime! // TIME:
ST_DrawPatchFromHud(HUD_TIME, (downwards ? sboredtime : sbotime), V_HUDTRANS);
if (downwards) // overtime!
return; return;
if (cv_timetic.value == 3) // Tics only -- how simple is this? if (cv_timetic.value == 3) // Tics only -- how simple is this?