diff --git a/src/d_netcmd.c b/src/d_netcmd.c index bb376132c..b4e256d4d 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -354,6 +354,8 @@ consvar_t cv_sharedstarposts = {"sharedstarposts", "On", CV_NETVAR, CV_OnOff, NU static CV_PossibleValue_t respawntype_cons_t[] = {{0, "Request"}, {1, "Starpost"}, {0, NULL}}; consvar_t cv_respawntype = {"respawntype", "Starpost", CV_NETVAR|CV_CHEAT, respawntype_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_steallives = {"steallives", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}}; consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "All"}, {0, NULL}}; @@ -505,8 +507,6 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_hidetime); CV_RegisterVar(&cv_inttime); - CV_RegisterVar(&cv_sharedstarposts); - CV_RegisterVar(&cv_respawntype); CV_RegisterVar(&cv_advancemap); CV_RegisterVar(&cv_playersforexit); CV_RegisterVar(&cv_timelimit); @@ -514,6 +514,10 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_forceskin); CV_RegisterVar(&cv_downloading); + CV_RegisterVar(&cv_sharedstarposts); + CV_RegisterVar(&cv_respawntype); + CV_RegisterVar(&cv_steallives); + CV_RegisterVar(&cv_specialrings); CV_RegisterVar(&cv_powerstones); CV_RegisterVar(&cv_competitionboxes); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 8f9717840..0695d503d 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -89,7 +89,7 @@ extern consvar_t cv_recycler; extern consvar_t cv_itemfinder; -extern consvar_t cv_inttime, cv_sharedstarposts, cv_respawntype, cv_advancemap, cv_playersforexit; +extern consvar_t cv_inttime, cv_sharedstarposts, cv_respawntype, cv_steallives, cv_advancemap, cv_playersforexit; extern consvar_t cv_overtime; extern consvar_t cv_startinglives; diff --git a/src/p_inter.c b/src/p_inter.c index 93a33e984..cf3f29993 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1309,7 +1309,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) players[i].starpostangle = special->angle; players[i].starpostnum = special->health; - if (cv_respawntype.value == 1 && players[i].lives > 0 && players[i].playerstate == PST_DEAD) + if (cv_respawntype.value == 1 && (P_GetLives(&players[i]) || players[i].lives > 0) && players[i].playerstate == PST_DEAD) players[i].playerstate = PST_REBORN; } } diff --git a/src/p_local.h b/src/p_local.h index a2831222a..117eaee1d 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -198,6 +198,7 @@ void P_PlayLivesJingle(player_t *player); #define P_PlayDeathSound(s) S_StartSound(s, sfx_altdi1 + P_RandomKey(4)); #define P_PlayVictorySound(s) S_StartSound(s, sfx_victr1 + P_RandomKey(4)); +boolean P_GetLives(player_t *player); // // P_MOBJ diff --git a/src/p_user.c b/src/p_user.c index bfad339c0..66233568f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8098,6 +8098,51 @@ void P_FindEmerald(void) return; } +// +// P_GetLives +// Steal lives if you're allowed to. +// + +boolean P_GetLives(player_t *player) +{ + INT32 i, maxlivesplayer = -1, livescheck = 1; + if (!(cv_steallives.value + && (gametype == GT_COOP) + && (netgame || multiplayer))) + return true; + + if (player->lives > 0) + return true; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (players[i].spectator) // Ignore spectators + continue; + + if (players[i].lives > livescheck) + { + maxlivesplayer = i; + livescheck = players[i].lives; + } + } + if (maxlivesplayer != -1) + { + if (players[maxlivesplayer].mo) + S_StartSound(players[maxlivesplayer].mo, sfx_jshard); // placeholder + P_GivePlayerLives(&players[maxlivesplayer], -1); + P_GivePlayerLives(player, 1); + if (netgame && P_IsLocalPlayer(player)) + S_ChangeMusic(mapmusname, mapmusflags, true); + else if (player == &players[displayplayer] || player == &players[secondarydisplayplayer]) + P_RestoreMusic(player); + return true; + } + return false; +} + // // P_DeathThink // Fall on your face when dying. @@ -8106,6 +8151,8 @@ void P_FindEmerald(void) static void P_DeathThink(player_t *player) { + INT32 j = MAXPLAYERS; + ticcmd_t *cmd = &player->cmd; player->deltaviewheight = 0; @@ -8121,10 +8168,31 @@ static void P_DeathThink(player_t *player) G_UseContinue(); // Even if we don't have one this handles ending the game } + if (cv_steallives.value + && (gametype == GT_COOP) + && (netgame || multiplayer) + && (player->lives <= 0)) + { + for (j = 0; j < MAXPLAYERS; j++) + { + if (!playeringame[j]) + continue; + + if (players[j].spectator) // Ignore spectators + continue; + + if (players[j].bot) // ignore dumb, stupid tails + continue; + + if (players[j].lives > 1) + break; + } + } + // 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 && !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_respawntype.value == 1) // Shamelessly lifted from TD. Thanks, Sryder! { @@ -8162,6 +8230,9 @@ static void P_DeathThink(player_t *player) player->playerstate = PST_REBORN; else switch(gametype) { case GT_COOP: + if (player->deadtimer > TICRATE && P_GetLives(player)) + player->playerstate = PST_REBORN; + break; case GT_COMPETITION: if (player->deadtimer > TICRATE) player->playerstate = PST_REBORN; diff --git a/src/st_stuff.c b/src/st_stuff.c index 8e40f138c..f6dedf449 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -731,6 +731,31 @@ static void ST_drawLives(void) // lives V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, va("%d",stplyr->lives)); + + if (cv_steallives.value + && (gametype == GT_COOP) + && (netgame || multiplayer)) + { + INT32 i, sum = 0; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (players[i].spectator) // Ignore spectators + continue; + + if (&players[i] == stplyr) + continue; + + if (players[i].lives < 2) + continue; + + sum += (players[i].lives - 1); + } + V_DrawString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANSHALF|v_splitflag, va("/%d",sum)); + } } static void ST_drawLevelTitle(void) @@ -1826,6 +1851,30 @@ static void ST_overlayDrawer(void) p = sboover; V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, STRINGY(BASEVIDHEIGHT/2 - (SHORT(p->height)/2)), 0, p); + + if (cv_steallives.value + && (gametype == GT_COOP) + && (netgame || multiplayer)) + { + INT32 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (players[i].spectator) // Ignore spectators + continue; + + if (&players[i] == stplyr) + continue; + + if (players[i].lives > 1) + break; + } + + if (i != MAXPLAYERS) + V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(BASEVIDHEIGHT/2 + (SHORT(p->height)/2)) + 15, 0, M_GetText("You'll steal a life on respawn.")); + } }