diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 01e94485d..2ce395769 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2415,7 +2415,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) // the remaining players. if (G_IsSpecialStage(gamemap)) { - INT32 i, count, increment, spheres; + INT32 i, count, sincrement, spheres, rincrement, rings; for (i = 0, count = 0; i < MAXPLAYERS; i++) { @@ -2425,18 +2425,35 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) count--; spheres = players[playernum].spheres; - increment = spheres/count; + rings = players[playernum].rings; + sincrement = spheres/count; + rincrement = rings/count; for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && i != playernum) { - if (spheres < increment) + if (spheres < 2*sincrement) + { P_GivePlayerSpheres(&players[i], spheres); + spheres = 0; + } else - P_GivePlayerSpheres(&players[i], increment); + { + P_GivePlayerSpheres(&players[i], sincrement); + spheres -= sincrement; + } - spheres -= increment; + if (rings < 2*rincrement) + { + P_GivePlayerRings(&players[i], rings); + rings = 0; + } + else + { + P_GivePlayerRings(&players[i], rincrement); + rings -= rincrement; + } } } } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3e82fc60c..ba28b19a2 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2706,14 +2706,6 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } } - // Clear player score and rings if a spectator. - if (players[playernum].spectator) - { - players[playernum].score = players[playernum].rings = 0; - if (players[playernum].mo) - players[playernum].mo->health = 1; - } - // In tag, check to see if you still have a game. if (G_TagGametype()) P_CheckSurvivors(); @@ -3600,7 +3592,7 @@ static void CoopLives_OnChange(void) { case 0: CONS_Printf(M_GetText("Players can now respawn indefinitely.\n")); - return; + break; case 1: CONS_Printf(M_GetText("Lives are now per-player.\n")); return; diff --git a/src/g_game.c b/src/g_game.c index d5faf6846..1630f085b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -215,7 +215,7 @@ UINT16 spacetimetics = 11*TICRATE + (TICRATE/2); UINT16 extralifetics = 4*TICRATE; UINT16 nightslinktics = 2*TICRATE; -INT32 gameovertics = 15*TICRATE; +INT32 gameovertics = 10*TICRATE; UINT8 ammoremovaltics = 2*TICRATE; @@ -2145,6 +2145,8 @@ void G_PlayerReborn(INT32 player) boolean outofcoop; INT16 bot; SINT8 pity; + INT16 rings; + INT16 spheres; score = players[player].score; lives = players[player].lives; @@ -2199,6 +2201,17 @@ void G_PlayerReborn(INT32 player) bot = players[player].bot; pity = players[player].pity; + if (!G_IsSpecialStage(gamemap)) + { + rings = (ultimatemode ? 0 : mapheaderinfo[gamemap-1]->startrings); + spheres = 0; + } + else + { + rings = players[player].rings; + spheres = players[player].spheres; + } + p = &players[player]; memset(p, 0, sizeof (*p)); @@ -2252,6 +2265,8 @@ void G_PlayerReborn(INT32 player) if (bot) p->bot = 1; // reset to AI-controlled p->pity = pity; + p->rings = rings; + p->spheres = spheres; // Don't do anything immediately p->pflags |= PF_USEDOWN; @@ -2259,7 +2274,6 @@ void G_PlayerReborn(INT32 player) p->pflags |= PF_JUMPDOWN; p->playerstate = PST_LIVE; - p->rings = p->spheres = 0; // 0 rings p->panim = PA_IDLE; // standing animation //if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there @@ -2370,8 +2384,6 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) P_SpawnPlayer(playernum); - players[playernum].rings = mapheaderinfo[gamemap-1]->startrings; - if (starpost) //Don't even bother with looking for a place to spawn. { P_MovePlayerToStarpost(playernum); diff --git a/src/p_inter.c b/src/p_inter.c index 0030e8e58..9025e2664 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3500,7 +3500,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return true; } - if (G_IsSpecialStage(gamemap)) + if (G_IsSpecialStage(gamemap) && !(damagetype & DMG_DEATHMASK)) { P_SpecialStageDamage(player, inflictor, source); return true; @@ -3524,10 +3524,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Instant-Death if (damagetype & DMG_DEATHMASK) - { P_KillPlayer(player, source, damage); - player->rings = player->spheres = 0; - } else if (metalrecording) { if (!inflictor) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1ee90d250..abf5de87d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10397,7 +10397,7 @@ void P_SpawnPlayer(INT32 playernum) && ((leveltime > 0 && ((G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) // late join special stage || (cv_coopstarposts.value == 2 && (p->jointime < 1 || p->outofcoop)))) // late join or die in new coop - || (((cv_cooplives.value == 1) || !P_GetLives(p)) && p->lives <= 0))); // game over and can't redistribute lives + || (!P_GetLives(p) && p->lives <= 0))); // game over and can't redistribute lives } else { @@ -10464,7 +10464,6 @@ void P_SpawnPlayer(INT32 playernum) P_SetupStateAnimation(mobj, mobj->state); mobj->health = 1; - p->rings = p->spheres = 0; p->playerstate = PST_LIVE; p->bonustime = false; diff --git a/src/p_user.c b/src/p_user.c index a69bd5b93..08579e48d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9027,19 +9027,22 @@ boolean P_GetLives(player_t *player) INT32 i, maxlivesplayer = -1, livescheck = 1; if (!(netgame || multiplayer) || (gametype != GT_COOP) - || (cv_cooplives.value == 1) || (player->lives == INFLIVES)) return true; - if ((cv_cooplives.value == 2 || cv_cooplives.value == 0) && player->lives > 0) - return true; - if (cv_cooplives.value == 0) // infinite lives { - player->lives++; + if (player->lives < 1) + player->lives = 1; return true; } + if ((cv_cooplives.value == 2 || cv_cooplives.value == 1) && player->lives > 0) + return true; + + if (cv_cooplives.value == 1) + return false; + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) @@ -9146,7 +9149,7 @@ static void P_DeathThink(player_t *player) // continue logic if (!(netgame || multiplayer) && player->lives <= 0) { - if (player->deadtimer > TICRATE && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0) + if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0) G_UseContinue(); else if (player->deadtimer >= gameovertics) G_UseContinue(); // Even if we don't have one this handles ending the game @@ -9170,12 +9173,12 @@ static void P_DeathThink(player_t *player) // Force respawn if idle for more than 30 seconds in shooter modes. if (player->deadtimer > 30*TICRATE && !G_PlatformGametype()) player->playerstate = PST_REBORN; - else if ((player->lives > 0 || j != MAXPLAYERS) && !G_IsSpecialStage(gamemap)) // Don't allow "click to respawn" in special stages! + else if ((player->lives > 0 || j != MAXPLAYERS) && !(G_IsSpecialStage(gamemap))) // Don't allow "click to respawn" in special stages! { if (gametype == GT_COOP && (netgame || multiplayer) && cv_coopstarposts.value == 2) { P_ConsiderAllGone(); - if ((player->deadtimer > 5*TICRATE) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE))) + if ((player->deadtimer > TICRATE<<1) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE))) { //player->spectator = true; player->outofcoop = true; @@ -9191,16 +9194,11 @@ static void P_DeathThink(player_t *player) player->playerstate = PST_REBORN; else switch(gametype) { case GT_COOP: - if (player->deadtimer > TICRATE) - player->playerstate = PST_REBORN; - break; case GT_COMPETITION: + case GT_RACE: if (player->deadtimer > TICRATE) player->playerstate = PST_REBORN; break; - case GT_RACE: - player->playerstate = PST_REBORN; - break; default: if (player->deadtimer > cv_respawntime.value*TICRATE) player->playerstate = PST_REBORN; @@ -9209,7 +9207,7 @@ static void P_DeathThink(player_t *player) } // Single player auto respawn - if (!(netgame || multiplayer) && player->deadtimer > 5*TICRATE) + if (!(netgame || multiplayer) && player->deadtimer > TICRATE<<1) player->playerstate = PST_REBORN; } } @@ -11011,8 +11009,6 @@ void P_PlayerThink(player_t *player) { if (gametype != GT_COOP) player->score = 0; - player->mo->health = 1; - player->rings = player->spheres = 0; } else if ((netgame || multiplayer) && player->lives <= 0 && gametype != GT_COOP) { diff --git a/src/st_stuff.c b/src/st_stuff.c index 142cd3e61..0db72efd1 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -66,8 +66,6 @@ patch_t *sboperiod; // Period for time centiseconds patch_t *livesback; // Lives icon background static patch_t *nrec_timer; // Timer for NiGHTS records static patch_t *sborings; -static patch_t *sboover; -static patch_t *timeover; static patch_t *stlivex; static patch_t *sboredrings; static patch_t *sboredtime; @@ -253,8 +251,6 @@ void ST_LoadGraphics(void) sbocolon = W_CachePatchName("STTCOLON", PU_HUDGFX); // Colon for time sboperiod = W_CachePatchName("STTPERIO", PU_HUDGFX); // Period for time centiseconds - sboover = W_CachePatchName("SBOOVER", PU_HUDGFX); - timeover = W_CachePatchName("TIMEOVER", PU_HUDGFX); stlivex = W_CachePatchName("STLIVEX", PU_HUDGFX); livesback = W_CachePatchName("STLIVEBK", PU_HUDGFX); nrec_timer = W_CachePatchName("NGRTIMER", PU_HUDGFX); // Timer for NiGHTS @@ -768,7 +764,12 @@ static inline void ST_drawRings(void) ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); - ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0)); + if (objectplacing) + ringnum = op_currentdoomednum; + else if (stplyr->rings < 0 || stplyr->spectator || stplyr->playerstate == PST_REBORN) + ringnum = 0; + else + ringnum = stplyr->rings; if (cv_timetic.value == 2) // Yes, even in modeattacking ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); @@ -877,6 +878,8 @@ static void ST_drawLivesArea(void) '\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false); else { + if (stplyr->playerstate == PST_DEAD && !(stplyr->spectator) && (livescount || stplyr->deadtimer < (TICRATE<<1))) + livescount++; if (livescount > 99) livescount = 99; V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, @@ -1960,7 +1963,7 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I static void ST_drawMatchHUD(void) { - char penaltystr[5]; + char penaltystr[7]; const INT32 y = 176; // HUD_LIVES INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6; @@ -2409,25 +2412,20 @@ static void ST_overlayDrawer(void) } } - // GAME OVER pic + // GAME OVER hud if ((gametype == GT_COOP) && (netgame || multiplayer) && (cv_cooplives.value == 0)) ; else if (G_GametypeUsesLives() && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer))) { - patch_t *p; - - if (countdown == 1) - p = timeover; - else - p = sboover; + INT32 i = MAXPLAYERS; + INT32 deadtimer = stplyr->spectator ? TICRATE : (stplyr->deadtimer-(TICRATE<<1)); if ((gametype == GT_COOP) && (netgame || multiplayer) && (cv_cooplives.value != 1)) { - INT32 i; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) @@ -2437,15 +2435,21 @@ static void ST_overlayDrawer(void) continue; if (players[i].lives > 0) - { - p = NULL; break; - } } } - if (p) - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, BASEVIDHEIGHT/2 - (SHORT(p->height)/2), V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS), p); + if (i == MAXPLAYERS && deadtimer >= 0) + { + const char *first = (countdown == 1) ? "TIME" : "GAME"; + const char *second = "OVER"; + INT32 w1 = V_LevelNameWidth(first), w2 = (w1 + 16 + V_LevelNameWidth(second))>>1; + INT32 lvlttlx1 = min(6*deadtimer, BASEVIDWIDTH/2), lvlttlx2 = BASEVIDWIDTH - lvlttlx1; + UINT32 flags = V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS); + + V_DrawLevelTitle(lvlttlx1 - w2, (BASEVIDHEIGHT-16)>>1, flags, first); + V_DrawLevelTitle(lvlttlx2 + w1 + 16 - w2, (BASEVIDHEIGHT-16)>>1, flags, "OVER"); + } } if (G_GametypeHasTeams())