diff --git a/src/k_battle.c b/src/k_battle.c index 9444dd78b..38b86abaf 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -93,6 +93,9 @@ void K_CheckBumpers(void) UINT8 i; UINT8 numingame = 0; UINT8 nobumpers = 0; + UINT8 eliminated = 0; + + const boolean singleplayer = (battlecapsules || bossinfo.valid); if (!(gametyperules & GTR_BUMPERS)) return; @@ -114,21 +117,28 @@ void K_CheckBumpers(void) { nobumpers++; } + + if (players[i].pflags & PF_ELIMINATED) + { + eliminated++; + } } - if (battlecapsules || bossinfo.valid) + if (singleplayer + ? nobumpers > 0 && nobumpers >= numingame + : eliminated >= numingame - 1) { - if (nobumpers > 0 && nobumpers >= numingame) + for (i = 0; i < MAXPLAYERS; i++) { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - if (players[i].spectator) - continue; + if (!playeringame[i]) + continue; + if (players[i].spectator) + continue; + + if (singleplayer) players[i].pflags |= PF_NOCONTEST; - P_DoPlayerExit(&players[i]); - } + + P_DoPlayerExit(&players[i]); } return; } diff --git a/src/p_inter.c b/src/p_inter.c index 7204741e2..ff4b9f916 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1934,13 +1934,12 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, return false; } - K_DestroyBumpers(player, 1); - switch (type) { case DMG_DEATHPIT: // Respawn kill types K_DoIngameRespawn(player); + player->mo->health -= K_DestroyBumpers(player, 1); return false; case DMG_SPECTATOR: // disappearifies, but still gotta put items back in play @@ -1997,10 +1996,11 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, P_SetTarget(&boom->target, player->mo); } - K_DestroyBumpers(player, player->bumpers); player->pflags |= PF_ELIMINATED; } + K_DestroyBumpers(player, player->bumpers); + return true; } diff --git a/src/p_local.h b/src/p_local.h index eb4633ff4..973af8621 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -66,6 +66,10 @@ extern "C" { #define P_GetPlayerViewHeight(player) (41*player->mo->height/48) +#ifdef PARANOIA +#define SCRAMBLE_REMOVED // Force debug build to crash when Removed mobj is accessed +#endif + typedef enum { THINK_POLYOBJ, @@ -284,6 +288,9 @@ extern mapthing_t *itemrespawnque[ITEMQUESIZE]; extern tic_t itemrespawntime[ITEMQUESIZE]; extern size_t iquehead, iquetail; extern consvar_t cv_gravity, cv_movebob; +#ifdef SCRAMBLE_REMOVED +extern consvar_t cv_scrambleremoved; +#endif void P_RespawnBattleBoxes(void); mobjtype_t P_GetMobjtype(UINT16 mthingtype); diff --git a/src/p_mobj.c b/src/p_mobj.c index 6bd6cbd79..4dfc6f525 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -53,6 +53,8 @@ static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); +consvar_t cv_scrambleremoved = CVAR_INIT ("scrambleremoved", "On", CV_NETVAR, CV_OnOff, NULL); + actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; @@ -11119,9 +11121,6 @@ mapthing_t *itemrespawnque[ITEMQUESIZE]; tic_t itemrespawntime[ITEMQUESIZE]; size_t iquehead, iquetail; -#ifdef PARANOIA -#define SCRAMBLE_REMOVED // Force debug build to crash when Removed mobj is accessed -#endif void P_RemoveMobj(mobj_t *mobj) { I_Assert(mobj != NULL); @@ -11257,7 +11256,10 @@ void P_RemoveMobj(mobj_t *mobj) // DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error. #ifdef SCRAMBLE_REMOVED // Invalidate mobj_t data to cause crashes if accessed! - memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t)); + if (cv_scrambleremoved.value) + { + memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t)); + } #endif } diff --git a/src/p_user.c b/src/p_user.c index 3d290a678..7b9d4205c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -60,6 +60,7 @@ #include "k_follower.h" #include "k_battle.h" #include "k_rank.h" +#include "k_director.h" #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -2786,11 +2787,23 @@ static void P_DeathThink(player_t *player) } } + if ((player->pflags & PF_ELIMINATED) && (gametyperules & GTR_BUMPERS)) + { + playerGone = true; + } + if (playerGone == false && player->deadtimer > TICRATE) { player->playerstate = PST_REBORN; } + // TODO: support splitscreen + // Spectate another player after 2 seconds + if (player == &players[consoleplayer] && playerGone == true && (gametyperules & GTR_BUMPERS) && player->deadtimer == 2*TICRATE) + { + K_ToggleDirector(true); + } + // Keep time rolling if (!(player->exiting || mapreset) && !(player->pflags & PF_NOCONTEST) && !stoppedclock) { diff --git a/src/r_main.c b/src/r_main.c index 0dfe36d38..2b9105c05 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1666,6 +1666,9 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_maxportals); CV_RegisterVar(&cv_movebob); +#ifdef SCRAMBLE_REMOVED + CV_RegisterVar(&cv_scrambleremoved); +#endif // Frame interpolation/uncapped CV_RegisterVar(&cv_fpscap);