diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 125e9d2c3..bb376132c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -347,7 +347,12 @@ consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NUL #endif // Intermission time Tails 04-19-2002 static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}}; -consvar_t cv_inttime = {"inttime", "20", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_inttime = {"inttime", "10", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_sharedstarposts = {"sharedstarposts", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + +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}; 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}; @@ -500,6 +505,8 @@ 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); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 80481c6a5..8f9717840 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_advancemap, cv_playersforexit; +extern consvar_t cv_inttime, cv_sharedstarposts, cv_respawntype, cv_advancemap, cv_playersforexit; extern consvar_t cv_overtime; extern consvar_t cv_startinglives; diff --git a/src/g_game.c b/src/g_game.c index 40878a70f..0a571c7fe 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2486,6 +2486,19 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo) } } +#ifdef HAVE_BLUA +#define RESETMAP {\ + LUAh_MapChange();\ + G_DoLoadLevel(true);\ + return;\ + } +#else +#define RESETMAP {\ + G_DoLoadLevel(true);\ + return;\ + } +#endif + // // G_DoReborn // @@ -2575,20 +2588,33 @@ void G_DoReborn(INT32 playernum) } } else -#ifdef HAVE_BLUA - { - LUAh_MapChange(); -#endif - G_DoLoadLevel(true); -#ifdef HAVE_BLUA - } -#endif + RESETMAP; } else { // respawn at the start mobj_t *oldmo = NULL; + if (gametype == GT_COOP && (netgame || multiplayer) && cv_respawntype.value == 1) + { + INT32 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!(playeringame[i] && players[i].mo && players[i].mo->health && players[i].playerstate == PST_LIVE)) + continue; + + if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators + continue; + + if (players[i].bot) // ignore dumb, stupid tails + continue; + + break; + } + if (i == MAXPLAYERS) + RESETMAP; + } + if (player->starposttime) starpost = true; @@ -2608,10 +2634,44 @@ void G_DoReborn(INT32 playernum) void G_AddPlayer(INT32 playernum) { + INT32 countplayers = 0, notexiting = 0; + player_t *p = &players[playernum]; + // Go through the current players and make sure you have the latest starpost set + if (G_PlatformGametype() && (netgame || multiplayer)) + { + INT32 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (players[i].bot) // ignore dumb, stupid tails + continue; + + countplayers++; + + if (!players->exiting) + notexiting++; + + if (!(cv_sharedstarposts.value && (gametype == GT_COOP) && (p->starpostnum < players[i].starpostnum))) + continue; + + p->starposttime = players[i].starposttime; + p->starpostx = players[i].starpostx; + p->starposty = players[i].starposty; + p->starpostz = players[i].starpostz; + p->starpostangle = players[i].starpostangle; + p->starpostnum = players[i].starpostnum; + } + } + p->jointime = 0; p->playerstate = PST_REBORN; + + if (countplayers && !notexiting) + P_DoPlayerExit(p); } void G_ExitLevel(void) diff --git a/src/p_enemy.c b/src/p_enemy.c index 4b8d14170..860feb916 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2835,8 +2835,8 @@ void A_BossDeath(mobj_t *mo) // make sure there is a player alive for victory for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && ((players[i].mo && players[i].mo->health > 0) - || ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0)))) + if (playeringame[i] && ((players[i].mo && players[i].mo->health) + || ((netgame || multiplayer) && (players[i].lives || players[i].continues)))) break; if (i == MAXPLAYERS) @@ -3280,10 +3280,28 @@ void A_ExtraLife(mobj_t *actor) // In shooter gametypes, give the player 100 rings instead of an extra life. if (gametype != GT_COOP && gametype != GT_COMPETITION) + { P_GivePlayerRings(player, 100); + P_PlayLivesJingle(player); + } else - P_GivePlayerLives(player, 1); - P_PlayLivesJingle(player); + { + INT32 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators + continue; + + if (players[i].bot) + continue; + + P_GivePlayerLives(&players[i], 1); + P_PlayLivesJingle(&players[i]); + } + } } // Function: A_BombShield @@ -9389,8 +9407,8 @@ void A_ForceWin(mobj_t *actor) for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && ((players[i].mo && players[i].mo->health > 0) - || ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0)))) + if (playeringame[i] && ((players[i].mo && players[i].mo->health) + || ((netgame || multiplayer) && (players[i].lives || players[i].continues)))) break; } diff --git a/src/p_inter.c b/src/p_inter.c index 2b8006534..02ed67a12 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1293,13 +1293,40 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->starpostnum >= special->health) return; // Already hit this post - // Save the player's time and position. - player->starposttime = leveltime; - player->starpostx = toucher->x>>FRACBITS; - player->starposty = toucher->y>>FRACBITS; - player->starpostz = special->z>>FRACBITS; - player->starpostangle = special->angle; - player->starpostnum = special->health; + if (cv_sharedstarposts.value && gametype == GT_COOP && (netgame || multiplayer)) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + if (players[i].bot) // ignore dumb, stupid tails + continue; + + players[i].starposttime = leveltime; + players[i].starpostx = player->mo->x>>FRACBITS; + players[i].starposty = player->mo->y>>FRACBITS; + players[i].starpostz = special->z>>FRACBITS; + players[i].starpostangle = special->angle; + players[i].starpostnum = special->health; + + if (cv_respawntype.value == 1 && players[i].playerstate == PST_DEAD) + players[i].playerstate = PST_REBORN; + } + } + S_StartSound(NULL, special->info->painsound); + } + else + { + // Save the player's time and position. + player->starposttime = leveltime; + player->starpostx = toucher->x>>FRACBITS; + player->starposty = toucher->y>>FRACBITS; + player->starpostz = special->z>>FRACBITS; + player->starpostangle = special->angle; + player->starpostnum = special->health; + S_StartSound(toucher, special->info->painsound); + } + P_ClearStarPost(special->health); // Find all starposts in the level with this value. diff --git a/src/p_user.c b/src/p_user.c index 8ce1d08d7..63e9feae7 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8105,22 +8105,60 @@ static void P_DeathThink(player_t *player) player->playerstate = PST_REBORN; else if (player->lives > 0 && !G_IsSpecialStage(gamemap)) // Don't allow "click to respawn" in special stages! { - // Respawn with jump button, force respawn time (3 second default, cheat protected) in shooter modes. - if ((cmd->buttons & BT_JUMP) && player->deadtimer > cv_respawntime.value*TICRATE - && gametype != GT_RACE && gametype != GT_COOP) - player->playerstate = PST_REBORN; + if (gametype == GT_COOP && (netgame || multiplayer) && cv_respawntype.value == 1) // Shamelessly lifted from TD. Thanks, Sryder! + { + INT32 i, lastdeadplayer = -1, deadtimercheck = INT32_MAX; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; - // Instant respawn in race or if you're spectating. - if ((cmd->buttons & BT_JUMP) && (gametype == GT_RACE || player->spectator)) - player->playerstate = PST_REBORN; + if (players[i].spectator) // Ignore spectators + continue; - // One second respawn in coop. - if ((cmd->buttons & BT_JUMP) && player->deadtimer > TICRATE && (gametype == GT_COOP || gametype == GT_COMPETITION)) - player->playerstate = PST_REBORN; + if (players[i].bot) // ignore dumb, stupid tails + continue; - // Single player auto respawn - if (!(netgame || multiplayer) && player->deadtimer > 5*TICRATE) - player->playerstate = PST_REBORN; + if (players[i].playerstate != PST_DEAD) + break; + + if (players[i].lives && players[i].deadtimer < deadtimercheck) + { + lastdeadplayer = i; + deadtimercheck = players[i].deadtimer; + } + } + + if (i == MAXPLAYERS && lastdeadplayer != -1 && deadtimercheck > 2*TICRATE) // the last killed player will reset the level in G_DoReborn + players[lastdeadplayer].playerstate = PST_REBORN; + } + else + { + // Respawn with jump button, force respawn time (3 second default, cheat protected) in shooter modes. + if (cmd->buttons & BT_JUMP) + { + if (player->spectator) + player->playerstate = PST_REBORN; + else switch(gametype) { + case GT_COOP: + case GT_COMPETITION: + 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; + break; + } + } + + // Single player auto respawn + if (!(netgame || multiplayer) && player->deadtimer > 5*TICRATE) + player->playerstate = PST_REBORN; + } } else if ((netgame || multiplayer) && player->deadtimer == 8*TICRATE) { @@ -8130,7 +8168,7 @@ static void P_DeathThink(player_t *player) INT32 i; for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && !players[i].exiting && players[i].lives > 0) + if (playeringame[i] && !players[i].exiting && players[i].lives) break; if (i == MAXPLAYERS) @@ -8147,7 +8185,7 @@ static void P_DeathThink(player_t *player) INT32 i; for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && (players[i].exiting || players[i].lives > 0)) + if (playeringame[i] && (players[i].exiting || players[i].lives)) break; if (i == MAXPLAYERS)