diff --git a/src/d_netcmd.c b/src/d_netcmd.c index f08c7554..aa28524a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2522,18 +2522,12 @@ static void Command_Teamchange_f(void) return; } - if (G_GametypeHasTeams()) - { - if (NetPacket.packet.newteam == (unsigned)players[consoleplayer].ctfteam || - (players[consoleplayer].spectator && !NetPacket.packet.newteam)) - error = true; - } - else if (G_GametypeHasSpectators()) - { - if ((players[consoleplayer].spectator && !NetPacket.packet.newteam) || - (!players[consoleplayer].spectator && NetPacket.packet.newteam == 3)) - error = true; - } + if (players[consoleplayer].spectator && !(players[consoleplayer].pflags & PF_WANTSTOJOIN) && !NetPacket.packet.newteam) + error = true; + else if (G_GametypeHasTeams() && NetPacket.packet.newteam == (unsigned)players[consoleplayer].ctfteam) + error = true; + else if (G_GametypeHasSpectators() && !players[consoleplayer].spectator && NetPacket.packet.newteam == 3) + error = true; #ifdef PARANOIA else I_Error("Invalid gametype after initial checks!"); @@ -2619,18 +2613,12 @@ static void Command_Teamchange2_f(void) return; } - if (G_GametypeHasTeams()) - { - if (NetPacket.packet.newteam == (unsigned)players[secondarydisplayplayer].ctfteam || - (players[secondarydisplayplayer].spectator && !NetPacket.packet.newteam)) - error = true; - } - else if (G_GametypeHasSpectators()) - { - if ((players[secondarydisplayplayer].spectator && !NetPacket.packet.newteam) || - (!players[secondarydisplayplayer].spectator && NetPacket.packet.newteam == 3)) - error = true; - } + if (players[secondarydisplayplayer].spectator && !(players[secondarydisplayplayer].pflags & PF_WANTSTOJOIN) && !NetPacket.packet.newteam) + error = true; + else if (G_GametypeHasTeams() && NetPacket.packet.newteam == (unsigned)players[secondarydisplayplayer].ctfteam) + error = true; + else if (G_GametypeHasSpectators() && !players[secondarydisplayplayer].spectator && NetPacket.packet.newteam == 3) + error = true; #ifdef PARANOIA else I_Error("Invalid gametype after initial checks!"); @@ -2716,18 +2704,12 @@ static void Command_Teamchange3_f(void) return; } - if (G_GametypeHasTeams()) - { - if (NetPacket.packet.newteam == (unsigned)players[thirddisplayplayer].ctfteam || - (players[thirddisplayplayer].spectator && !NetPacket.packet.newteam)) - error = true; - } - else if (G_GametypeHasSpectators()) - { - if ((players[thirddisplayplayer].spectator && !NetPacket.packet.newteam) || - (!players[thirddisplayplayer].spectator && NetPacket.packet.newteam == 3)) - error = true; - } + if (players[thirddisplayplayer].spectator && !(players[thirddisplayplayer].pflags & PF_WANTSTOJOIN) && !NetPacket.packet.newteam) + error = true; + else if (G_GametypeHasTeams() && NetPacket.packet.newteam == (unsigned)players[thirddisplayplayer].ctfteam) + error = true; + else if (G_GametypeHasSpectators() && !players[thirddisplayplayer].spectator && NetPacket.packet.newteam == 3) + error = true; #ifdef PARANOIA else I_Error("Invalid gametype after initial checks!"); @@ -2813,18 +2795,12 @@ static void Command_Teamchange4_f(void) return; } - if (G_GametypeHasTeams()) - { - if (NetPacket.packet.newteam == (unsigned)players[fourthdisplayplayer].ctfteam || - (players[fourthdisplayplayer].spectator && !NetPacket.packet.newteam)) - error = true; - } - else if (G_GametypeHasSpectators()) - { - if ((players[fourthdisplayplayer].spectator && !NetPacket.packet.newteam) || - (!players[fourthdisplayplayer].spectator && NetPacket.packet.newteam == 3)) - error = true; - } + if (players[fourthdisplayplayer].spectator && !(players[fourthdisplayplayer].pflags & PF_WANTSTOJOIN) && !NetPacket.packet.newteam) + error = true; + else if (G_GametypeHasTeams() && NetPacket.packet.newteam == (unsigned)players[fourthdisplayplayer].ctfteam) + error = true; + else if (G_GametypeHasSpectators() && !players[fourthdisplayplayer].spectator && NetPacket.packet.newteam == 3) + error = true; #ifdef PARANOIA else I_Error("Invalid gametype after initial checks!"); @@ -3024,24 +3000,23 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } // Prevent multiple changes in one go. - if (G_TagGametype()) + if (players[playernum].spectator && !(players[playernum].pflags & PF_WANTSTOJOIN) && !NetPacket.packet.newteam) + return; + else if (G_TagGametype()) { if (((players[playernum].pflags & PF_TAGIT) && NetPacket.packet.newteam == 1) || (!(players[playernum].pflags & PF_TAGIT) && NetPacket.packet.newteam == 2) || - (players[playernum].spectator && NetPacket.packet.newteam == 0) || (!players[playernum].spectator && NetPacket.packet.newteam == 3)) return; } else if (G_GametypeHasTeams()) { - if ((NetPacket.packet.newteam && (NetPacket.packet.newteam == (unsigned)players[playernum].ctfteam)) || - (players[playernum].spectator && !NetPacket.packet.newteam)) + if (NetPacket.packet.newteam && (NetPacket.packet.newteam == (unsigned)players[playernum].ctfteam)) return; } else if (G_GametypeHasSpectators()) { - if ((players[playernum].spectator && !NetPacket.packet.newteam) || - (!players[playernum].spectator && NetPacket.packet.newteam == 3)) + if (!players[playernum].spectator && NetPacket.packet.newteam == 3) return; } else @@ -3113,19 +3088,26 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } //Safety first! - if (players[playernum].mo) + // (not respawning spectators here...) + if (!players[playernum].spectator) { - if (!players[playernum].spectator) - P_DamageMobj(players[playernum].mo, NULL, NULL, 10000); - /*else + if (players[playernum].mo) { - P_RemoveMobj(players[playernum].mo); - players[playernum].mo = NULL; + //if (!players[playernum].spectator) + P_DamageMobj(players[playernum].mo, NULL, NULL, 10000); + /*else + { + if (players[playernum].mo) + { + P_RemoveMobj(players[playernum].mo); + players[playernum].mo = NULL; + } + players[playernum].playerstate = PST_REBORN; + }*/ + } + else players[playernum].playerstate = PST_REBORN; - }*/ } - else - players[playernum].playerstate = PST_REBORN; //Now that we've done our error checking and killed the player //if necessary, put the player on the correct team/status. @@ -3210,6 +3192,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } else if (NetPacket.packet.newteam == 3) /*CONS_Printf(M_GetText("%s entered the game.\n"), player_names[playernum])*/; + else if (players[playernum].pflags & PF_WANTSTOJOIN) + players[playernum].pflags &= ~PF_WANTSTOJOIN; else CONS_Printf(M_GetText("%s became a spectator.\n"), player_names[playernum]); diff --git a/src/g_game.c b/src/g_game.c index 8908d33c..322d49e4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2174,7 +2174,9 @@ void G_Ticker(boolean run) if (run) { - if (G_GametypeHasSpectators() && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING)) + if (G_GametypeHasSpectators() + && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING // definitely good + || gamestate == GS_WAITINGPLAYERS)) // definitely a problem if we don't do it at all in this gamestate, but might need more protection? K_CheckSpectateStatus(); if (pausedelay) diff --git a/src/k_kart.c b/src/k_kart.c index 106ffbd9..f969fe52 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4057,33 +4057,54 @@ void K_CheckBumpers(void) void K_CheckSpectateStatus(void) { UINT8 respawnlist[MAXPLAYERS]; - UINT8 i, no = 0; - UINT8 numingame = 0, numjoiners = 0; + UINT8 i, numingame = 0, numjoiners = 0; - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; + if (!cv_allowteamchange.value) + return; - if (!players[i].spectator) - { + // Get the number of players in game, and the players to be de-spectated. + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (!players[i].spectator) + { numingame++; - if (gamestate != GS_LEVEL) - continue; - if (G_RaceGametype() && players[i].laps > 0) - return; - } + continue; + } + else if (!(players[i].pflags & PF_WANTSTOJOIN)) + continue; - if (cv_allowteamchange.value && !(players[i].pflags & PF_WANTSTOJOIN)) - continue; + respawnlist[numjoiners++] = i; + } - respawnlist[no++] = i; - } + // literally zero point in going any further if nobody is joining + if (!numjoiners) + return; - numjoiners = no; // Move the map change stuff up here when it gets a delay, and remove this redundant numjoiners var + // Check if there are any conditions that should prevent de-spectating. + if ((gamestate == GS_LEVEL) && (numingame > 1)) + { + // If anyone's on lap two or up in a race gametype, HALT. + if (G_RaceGametype()) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; - while (no) - P_SpectatorJoinGame(&players[respawnlist[--no]]); + if (!players[i].laps) + continue; + + return; + } + } + } + + // Finally, we can de-spectate everyone! + for (i = 0; i < numjoiners; i++) + P_SpectatorJoinGame(&players[respawnlist[i]]); if (!server) return; diff --git a/src/m_menu.c b/src/m_menu.c index a88ddfbd..48857e20 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -535,6 +535,7 @@ static menuitem_t MPauseMenu[] = {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48}, {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48}, + {IT_STRING | IT_CALL, NULL, "Cancel Join", M_ConfirmSpectate, 48}, {IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 48}, {IT_CALL | IT_STRING, NULL, "Player Setup...", M_SetupMultiPlayer, 56}, // alone {IT_CALL | IT_STRING, NULL, "Options", M_Options, 64}, @@ -557,6 +558,7 @@ typedef enum #endif mpause_spectate, mpause_entergame, + mpause_canceljoin, mpause_switchteam, mpause_psetup, mpause_options, @@ -2842,6 +2844,7 @@ void M_StartControlPanel(void) #endif MPauseMenu[mpause_spectate].status = IT_DISABLED; MPauseMenu[mpause_entergame].status = IT_DISABLED; + MPauseMenu[mpause_canceljoin].status = IT_DISABLED; MPauseMenu[mpause_switchteam].status = IT_DISABLED; MPauseMenu[mpause_psetup].status = IT_DISABLED; // Reset these in case splitscreen messes things up @@ -2889,7 +2892,14 @@ void M_StartControlPanel(void) if (G_GametypeHasTeams()) MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU; else if (G_GametypeHasSpectators()) - MPauseMenu[((&players[consoleplayer] && players[consoleplayer].spectator) ? mpause_entergame : mpause_spectate)].status = IT_STRING | IT_CALL; + { + if (!players[consoleplayer].spectator) + MPauseMenu[mpause_spectate].status = IT_STRING | IT_CALL; + else if (players[consoleplayer].pflags & PF_WANTSTOJOIN) + MPauseMenu[mpause_canceljoin].status = IT_STRING | IT_CALL; + else + MPauseMenu[mpause_entergame].status = IT_STRING | IT_CALL; + } else // in this odd case, we still want something to be on the menu even if it's useless MPauseMenu[mpause_spectate].status = IT_GRAYEDOUT; } @@ -4207,11 +4217,11 @@ static void M_ConfirmSpectate(INT32 choice) static void M_ConfirmEnterGame(INT32 choice) { (void)choice; - if (!cv_allowteamchange.value) + /*if (!cv_allowteamchange.value) { M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); return; - } + }*/ M_ClearMenus(true); COM_ImmedExecute("changeteam playing"); } diff --git a/src/p_mobj.c b/src/p_mobj.c index e9603c43..45c0b725 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9830,8 +9830,13 @@ void P_SpawnPlayer(INT32 playernum) // spawn as spectator determination if (!G_GametypeHasSpectators()) p->spectator = false; - else if (netgame && p->jointime <= 1 && pcount > 1) + else if (netgame && p->jointime <= 1 && pcount) + { p->spectator = true; + if (pcount == 1) + p->pflags |= PF_WANTSTOJOIN; + p->jointime = 2; // HACK??????? + } else if (multiplayer && !netgame) { // If you're in a team game and you don't have a team assigned yet... @@ -9912,41 +9917,35 @@ void P_SpawnPlayer(INT32 playernum) overheadarrow->flags2 |= MF2_DONTDRAW; P_SetScale(overheadarrow, mobj->destscale); - if (p->spectator) // HEY! No being cheap... + if (p->spectator && pcount > 1) // HEY! No being cheap... p->kartstuff[k_bumper] = 0; else if (p->kartstuff[k_bumper] > 0 || leveltime < 1 || (p->jointime <= 1 && pcount <= 1)) { - INT32 i; - angle_t newangle; - angle_t diff; - fixed_t newx; - fixed_t newy; - mobj_t *mo; - if (leveltime < 1 || (p->jointime <= 1 && pcount <= 1)) // Start of the map? p->kartstuff[k_bumper] = cv_kartbumpers.value; // Reset those bumpers! - if (p->kartstuff[k_bumper] <= 1) - diff = 0; - else - diff = FixedAngle(360*FRACUNIT/p->kartstuff[k_bumper]); - - newangle = mobj->angle; - newx = mobj->x + P_ReturnThrustX(mobj, newangle + ANGLE_180, 64*FRACUNIT); - newy = mobj->y + P_ReturnThrustY(mobj, newangle + ANGLE_180, 64*FRACUNIT); - - for (i = 0; i < p->kartstuff[k_bumper]; i++) + if (p->kartstuff[k_bumper]) { - mo = P_SpawnMobj(newx, newy, mobj->z, MT_BATTLEBUMPER); - mo->threshold = i; - P_SetTarget(&mo->target, mobj); - mo->angle = (diff * (i-1)); - mo->color = mobj->color; - if (mobj->flags2 & MF2_DONTDRAW) - mo->flags2 |= MF2_DONTDRAW; - else - mo->flags2 &= ~MF2_DONTDRAW; + INT32 i; + angle_t diff = FixedAngle(360*FRACUNIT/p->kartstuff[k_bumper]); + angle_t newangle = mobj->angle; + fixed_t newx = mobj->x + P_ReturnThrustX(mobj, newangle + ANGLE_180, 64*FRACUNIT); + fixed_t newy = mobj->y + P_ReturnThrustY(mobj, newangle + ANGLE_180, 64*FRACUNIT); + mobj_t *mo; + + for (i = 0; i < p->kartstuff[k_bumper]; i++) + { + mo = P_SpawnMobj(newx, newy, mobj->z, MT_BATTLEBUMPER); + mo->threshold = i; + P_SetTarget(&mo->target, mobj); + mo->angle = (diff * (i-1)); + mo->color = mobj->color; + if (mobj->flags2 & MF2_DONTDRAW) + mo->flags2 |= MF2_DONTDRAW; + else + mo->flags2 &= ~MF2_DONTDRAW; + } } } else if (p->kartstuff[k_bumper] <= 0) diff --git a/src/p_user.c b/src/p_user.c index 03ea25a4..3d856233 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8812,7 +8812,7 @@ boolean P_SpectatorJoinGame(player_t *player) { if (P_IsLocalPlayer(player)) CONS_Printf(M_GetText("Server does not allow team change.\n")); - player->powers[pw_flashing] = 2*TICRATE; //to prevent message spam. + player->powers[pw_flashing] = TICRATE + 1; //to prevent message spam. } // Team changing in Team Match and CTF // Pressing fire assigns you to a team that needs players if allowed. @@ -9301,7 +9301,7 @@ void P_PlayerThink(player_t *player) if ((netgame || splitscreen) && player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing]) { player->pflags ^= PF_WANTSTOJOIN; - player->powers[pw_flashing] = 2*TICRATE; + player->powers[pw_flashing] = TICRATE + 1; /*if (P_SpectatorJoinGame(player)) return; // player->mo was removed.*/ } diff --git a/src/st_stuff.c b/src/st_stuff.c index aecfe34d..260a795b 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1952,7 +1952,9 @@ static void ST_overlayDrawer(void) { // SRB2kart: changed positions & text V_DrawString(2, BASEVIDHEIGHT-50, V_HUDTRANSHALF|V_YELLOWMAP, M_GetText("- SPECTATING -")); - if (stplyr->pflags & PF_WANTSTOJOIN) + if (stplyr->powers[pw_flashing] & 1) + ; + else if (stplyr->pflags & PF_WANTSTOJOIN) V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Item - Cancel Join")); /*else if (G_GametypeHasTeams()) V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Item - Join Team"));*/