diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 41279577f..92d67f224 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3875,22 +3875,14 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) CONS_Debug(DBG_NETPLAY, "addplayer: %d %d\n", node, newplayernum); - { - // Clear player before joining, lest some things get set incorrectly - CL_ClearPlayer(newplayernum); - G_DestroyParty(newplayernum); + G_AddPlayer(newplayernum); + //G_SpectatePlayerOnJoin(newplayernum); -- caused desyncs in this spot :( - playeringame[newplayernum] = true; - G_AddPlayer(newplayernum); - - if (newplayernum+1 > doomcom->numslots) - doomcom->numslots = (INT16)(newplayernum+1); - } + if (newplayernum+1 > doomcom->numslots) + doomcom->numslots = (INT16)(newplayernum+1); newplayer = &players[newplayernum]; - newplayer->jointime = 0; - READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME); READMEM(*p, players[newplayernum].public_key, PUBKEYLENGTH); READMEM(*p, clientpowerlevels[newplayernum], sizeof(((serverplayer_t *)0)->powerlevels)); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 003af15c4..83171f68a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1193,14 +1193,13 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) && LUA_HookTeamSwitch(&players[playernum], 0, false, false, false)) // fiiiine, lua can except it { P_DamageMobj(players[playernum].mo, NULL, NULL, 1, DMG_SPECTATOR); - players[playernum].playerstate = PST_REBORN; - players[playernum].pflags &= ~PF_WANTSTOJOIN; - players[playernum].spectator = true; + if (players[i].spectator) + { + HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false); - HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false); - - FinalisePlaystateChange(playernum); + FinalisePlaystateChange(playernum); + } } } } @@ -3452,6 +3451,22 @@ static void Command_ServerTeamChange_f(void) SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue)); } +void P_SetPlayerSpectator(INT32 playernum) +{ + //Make sure you're in the right gametype. + if (!G_GametypeHasTeams() && !G_GametypeHasSpectators()) + return; + + // Don't duplicate efforts. + if (players[playernum].spectator) + return; + + players[playernum].spectator = true; + players[playernum].pflags &= ~PF_WANTSTOJOIN; + + players[playernum].playerstate = PST_REBORN; +} + //todo: This and the other teamchange functions are getting too long and messy. Needs cleaning. static void Got_Teamchange(UINT8 **cp, INT32 playernum) { @@ -3523,55 +3538,38 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]); SendKick(playernum, KICK_MSG_CON_FAIL); + return; } //Safety first! // (not respawning spectators here...) wasspectator = (players[playernum].spectator == true); - - if (!wasspectator && gamestate == GS_LEVEL) - { - if (players[playernum].mo) - { - P_DamageMobj(players[playernum].mo, NULL, NULL, 1, - (NetPacket.packet.newteam ? DMG_INSTAKILL : DMG_SPECTATOR)); - } - //else - if (!NetPacket.packet.newteam) - { - players[playernum].playerstate = PST_REBORN; - } - } - players[playernum].pflags &= ~PF_WANTSTOJOIN; + if (!wasspectator) + { + if (gamestate == GS_LEVEL && players[playernum].mo) + { + // The following will call P_SetPlayerSpectator if successful + P_DamageMobj(players[playernum].mo, NULL, NULL, 1, DMG_SPECTATOR); + } + + //...but because the above could return early under some contexts, we try again here + P_SetPlayerSpectator(playernum); + } //Now that we've done our error checking and killed the player //if necessary, put the player on the correct team/status. - boolean nochangeoccourred = false; + + if (NetPacket.packet.newteam != 0) + { + // This serves us in both teamchange contexts. + players[playernum].pflags |= PF_WANTSTOJOIN; + } if (G_GametypeHasTeams()) { - if (!NetPacket.packet.newteam) - { - players[playernum].ctfteam = 0; - players[playernum].spectator = true; - } - else - { - players[playernum].ctfteam = NetPacket.packet.newteam; - players[playernum].pflags |= PF_WANTSTOJOIN; //players[playernum].spectator = false; - nochangeoccourred = true; - } - } - else if (G_GametypeHasSpectators()) - { - if (!NetPacket.packet.newteam) - players[playernum].spectator = true; - else - { - players[playernum].pflags |= PF_WANTSTOJOIN; //players[playernum].spectator = false; - nochangeoccourred = true; - } + // This one is, of course, specific. + players[playernum].ctfteam = NetPacket.packet.newteam; } if (NetPacket.packet.autobalance) @@ -3599,20 +3597,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) else if (NetPacket.packet.newteam == 0 && !wasspectator) HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false); // "entered the game" text was moved to P_SpectatorJoinGame - /*if (G_GametypeHasTeams()) - { - if (NetPacket.packet.newteam) - { - UINT8 i; - for (i = 0; i <= splitscreen; i++) - { - if (playernum == g_localplayers[i]) //CTF and Team Match colors. - CV_SetValue(&cv_playercolor[i], NetPacket.packet.newteam + 5); - -this calculation is totally wrong - } - } - }*/ - - if (gamestate != GS_LEVEL || nochangeoccourred == true) + if (gamestate != GS_LEVEL || wasspectator == true) return; FinalisePlaystateChange(playernum); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index ebd24b266..a2129195f 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -245,6 +245,7 @@ void D_SetupVote(void); void D_ModifyClientVote(UINT8 player, SINT8 voted); void D_PickVote(void); void ObjectPlace_OnChange(void); +void P_SetPlayerSpectator(INT32 playernum); boolean IsPlayerAdmin(INT32 playernum); void SetAdminPlayer(INT32 playernum); void ClearAdminPlayers(void); diff --git a/src/g_demo.c b/src/g_demo.c index 2a94b8af9..90959dc20 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -228,10 +228,7 @@ void G_ReadDemoExtraData(void) { if (!playeringame[p]) { - CL_ClearPlayer(p); - playeringame[p] = true; G_AddPlayer(p); - players[p].spectator = true; } for (i = 0; i < MAXAVAILABILITY; i++) @@ -253,28 +250,34 @@ void G_ReadDemoExtraData(void) switch (i) { case DXD_PST_PLAYING: - if (players[p].bot) + if (players[p].spectator == true) { - players[p].spectator = false; - } - else - { - players[p].pflags |= PF_WANTSTOJOIN; + if (players[p].bot) + { + players[p].spectator = false; + } + else + { + players[p].pflags |= PF_WANTSTOJOIN; + } } //CONS_Printf("player %s is despectating on tic %d\n", player_names[p], leveltime); break; case DXD_PST_SPECTATING: - players[p].pflags &= ~PF_WANTSTOJOIN; // double-fuck you - if (players[p].spectator != true) + if (players[p].spectator) { - //CONS_Printf("player %s is spectating on tic %d\n", player_names[p], leveltime); - players[p].spectator = true; - if (players[p].mo) - P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_INSTAKILL); - else - players[p].playerstate = PST_REBORN; + players[p].pflags &= ~PF_WANTSTOJOIN; } + else + { + if (players[p].mo) + { + P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_SPECTATOR); + } + P_SetPlayerSpectator(p); + } + break; case DXD_PST_LEFT: @@ -3420,7 +3423,7 @@ void G_DoPlayDemo(const char *defdemoname) if (!playeringame[displayplayers[0]] || players[displayplayers[0]].spectator) displayplayers[0] = consoleplayer = serverplayer = p; - playeringame[p] = true; + G_AddPlayer(p); players[p].spectator = spectator; if (flags & DEMO_KICKSTART) diff --git a/src/g_demo.h b/src/g_demo.h index 66e0705c1..96217a310 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -127,6 +127,8 @@ extern UINT8 demo_writerng; #define DXD_COLOR 0x10 // color changed #define DXD_FOLLOWER 0x20 // follower was changed +#define DXD_ADDPLAYER (DXD_JOINDATA|DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER) + #define DXD_WEAPONPREF 0x80 // netsynced playsim settings were changed #define DXD_PST_PLAYING 0x01 diff --git a/src/g_game.c b/src/g_game.c index a7377834c..1f16f07c3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2831,9 +2831,6 @@ void G_DoReborn(INT32 playernum) { player_t *player = &players[playernum]; - // Make sure objectplace is OFF when you first start the level! - OP_ResetObjectplace(); - { // respawn at the start mobj_t *oldmo = NULL; @@ -2854,11 +2851,53 @@ void G_DoReborn(INT32 playernum) } } +// These are the barest esentials. +// This func probably doesn't even need to know if the player is a bot. void G_AddPlayer(INT32 playernum) { - player_t *p = &players[playernum]; - p->playerstate = PST_REBORN; - demo_extradata[playernum] |= DXD_JOINDATA|DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER; // Set everything + CL_ClearPlayer(playernum); + G_DestroyParty(playernum); + + playeringame[playernum] = true; + + player_t *newplayer = &players[playernum]; + + newplayer->playerstate = PST_REBORN; + newplayer->jointime = 0; + + demo_extradata[playernum] |= DXD_ADDPLAYER; +} + +void G_SpectatePlayerOnJoin(INT32 playernum) +{ + // This is only ever called shortly after the above. + // That calls CL_ClearPlayer, so spectator is false by default + + if (!netgame && !G_GametypeHasTeams() && !G_GametypeHasSpectators()) + return; + + // These are handled automatically elsewhere + if (demo.playback || players[playernum].bot) + return; + + UINT8 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + // Spectators are of no consequence + if (players[i].spectator) + continue; + + // Prevent splitscreen hosters/joiners from only adding 1 player at a time in empty servers (this will also catch yourself) + if (!players[i].jointime) + continue; + + // A ha! An established player! It's time to spectate + players[playernum].spectator = true; + break; + } } void G_BeginLevelExit(void) @@ -3277,7 +3316,7 @@ boolean G_GametypeHasSpectators(void) #ifdef DEVELOP return true; #endif - return (netgame || (multiplayer && demo.netgame)); + return (netgame || (demo.playback && demo.netgame)); } // diff --git a/src/g_game.h b/src/g_game.h index b12124aef..d4f933df7 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -240,6 +240,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive); void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive); void G_AddPlayer(INT32 playernum); +void G_SpectatePlayerOnJoin(INT32 playernum); void G_SetExitGameFlag(void); void G_ClearExitGameFlag(void); diff --git a/src/k_battle.c b/src/k_battle.c index 7020e7fcf..64673953d 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -127,10 +127,7 @@ void K_CheckBumpers(void) { if (nobumpers > 0 && nobumpers >= numingame) { - // TODO: this would make a great debug feature for release -#ifndef DEVELOP P_DoAllPlayersExit(PF_NOCONTEST, false); -#endif return; } } @@ -142,9 +139,9 @@ void K_CheckBumpers(void) if (numingame <= 1) { - if ((gametyperules & GTR_PRISONS) && (K_CanChangeRules(true) == true)) + if ((gametyperules & GTR_PRISONS) && !battleprisons && (K_CanChangeRules(true) == true)) { - // Reset map to turn on battle capsules + // Reset map to turn on battle prisons if (server) D_MapChange(gamemap, gametype, encoremode, true, 0, false, false); } diff --git a/src/k_bot.c b/src/k_bot.c index 89c7cd244..2a634c415 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -47,12 +47,8 @@ void K_SetBot(UINT8 newplayernum, UINT8 skinnum, UINT8 difficulty, botStyle_e st { CONS_Debug(DBG_NETPLAY, "addbot: %d\n", newplayernum); - // Clear player before joining, lest some things get set incorrectly - CL_ClearPlayer(newplayernum); - G_DestroyParty(newplayernum); - - playeringame[newplayernum] = true; G_AddPlayer(newplayernum); + if (newplayernum+1 > doomcom->numslots) doomcom->numslots = (INT16)(newplayernum+1); diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 0d4b4b654..e4ab54aab 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -201,7 +201,7 @@ void K_InitGrandPrixBots(void) } else { - players[i].spectator = true; // force spectate for all other players, if they happen to exist? + P_SetPlayerSpectator(i); // force spectate for all other players, if they happen to exist? } } } @@ -391,6 +391,11 @@ void K_UpdateGrandPrixBots(void) players[i].spectator = !(gametyperules & GTR_BOTS) || (grandprixinfo.eventmode != GPEVENT_NONE); } + if (grandprixinfo.wonround == false) + { + return; + } + // Find the rival. for (i = 0; i < MAXPLAYERS; i++) { diff --git a/src/p_inter.c b/src/p_inter.c index 5645ddbc2..315e6e124 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1556,7 +1556,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_PlayDeathSound(target); } - if (K_Cooperative()) + // Prisons Free Play: don't eliminate P1 for + // spectating. Because in Free Play, this player + // can enter the game again, and these flags would + // make them intangible. + if (K_Cooperative() && !target->player->spectator) { target->player->pflags |= PF_ELIMINATED; @@ -2052,35 +2056,34 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 type) { - if (player->respawn.state != RESPAWNST_NONE) + if (type == DMG_SPECTATOR && (G_GametypeHasTeams() || G_GametypeHasSpectators())) { - K_DoInstashield(player); - return false; + P_SetPlayerSpectator(player-players); } - - if (!player->exiting && (specialstageinfo.valid == true || modeattacking & ATTACKING_SPB)) + else { - // TODO: this would make a great debug feature for release -#ifdef DEVELOP - if (type != DMG_SPECTATOR) + if (player->respawn.state != RESPAWNST_NONE) { - P_DoPlayerExit(player, PF_NOCONTEST); + K_DoInstashield(player); + return false; + } + + if (player->exiting) + { + player->mo->destscale = 1; + player->mo->flags |= MF_NOCLIPTHING; + return false; } -#else - P_DoPlayerExit(player, PF_NOCONTEST); -#endif if (specialstageinfo.valid == true) { HU_DoTitlecardCEcho(player, "FALL OUT!", false); + P_DoPlayerExit(player, PF_NOCONTEST); + } + else if (modeattacking & ATTACKING_SPB) + { + P_DoPlayerExit(player, PF_NOCONTEST); } - } - - if (player->exiting) - { - player->mo->destscale = 1; - player->mo->flags |= MF_NOCLIPTHING; - return false; } switch (type) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1a3e91375..51d038c28 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11830,61 +11830,24 @@ void P_RespawnSpecials(void) // void P_SpawnPlayer(INT32 playernum) { - UINT8 i, pcount = 0; // MAXPLAYERS if exiting + UINT8 i; player_t *p = &players[playernum]; mobj_t *mobj; + boolean justjoined = (p->jointime <= 1); + if (p->playerstate == PST_REBORN) { - G_PlayerReborn(playernum, (p->jointime <= 1)); + G_PlayerReborn(playernum, justjoined); } - for (i = 0; i < MAXPLAYERS; i++) - { - if (i == playernum) - continue; - if (!playeringame[i] || players[i].spectator) - continue; - if (players[i].exiting) - { - pcount = MAXPLAYERS; - break; - } - if (players[i].jointime <= 1) // Prevent splitscreen hosters/joiners from only adding 1 player at a time in empty servers - continue; - pcount++; - } + if (justjoined) + G_SpectatePlayerOnJoin(playernum); - // spawn as spectator determination - if (multiplayer && demo.playback) - { - ; // Don't mess with spectator values since the demo setup handles them already. - } - else if (p->bot) - { - if (K_PodiumSequence() == true) - ; // This is too late to correct spectator status. Whatever state we're in at this point, our (dog) bed is made. - else if (!(gametyperules & GTR_BOTS) - || (grandprixinfo.gp == true - && grandprixinfo.eventmode != GPEVENT_NONE)) - { - // Bots aren't supposed to be here. - p->spectator = true; - } - else - { - // No point in a spectating bot! - p->spectator = false; - } - } - else if (netgame && p->jointime <= 1 && pcount) - { - p->spectator = true; - } - else if (multiplayer && !netgame) + if (G_GametypeHasTeams()) { // If you're in a team game and you don't have a team assigned yet... - if (G_GametypeHasTeams() && p->ctfteam == 0) + if (!p->spectator && p->ctfteam == 0) { changeteam_union NetPacket; UINT16 usvalue; @@ -11894,9 +11857,6 @@ void P_SpawnPlayer(INT32 playernum) // yes even in splitscreen mode p->spectator = true; - if (playernum&1) p->skincolor = skincolor_redteam; - else p->skincolor = skincolor_blueteam; - // but immediately send a team change packet. NetPacket.packet.playernum = playernum; NetPacket.packet.verification = true; @@ -11905,22 +11865,6 @@ void P_SpawnPlayer(INT32 playernum) usvalue = SHORT(NetPacket.value.l|NetPacket.value.b); SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue)); } - else // Otherwise, never spectator. - { - // TODO: this would make a great debug feature for release -#ifndef DEVELOP - p->spectator = false; -#endif - } - } - - if (G_GametypeHasTeams()) - { - // Fix stupid non spectator spectators. - if (!p->spectator && !p->ctfteam) - { - p->spectator = true; - } // Fix team colors. // This code isn't being done right somewhere else. Oh well. @@ -12019,8 +11963,7 @@ void P_SpawnPlayer(INT32 playernum) S_StartSound(body, sfx_s1af); } - // I'm not refactoring the loop at the top of this file. - pcount = 0; + UINT8 pcount = 0; for (i = 0; i < MAXPLAYERS; ++i) { diff --git a/src/p_setup.c b/src/p_setup.c index e9281f11b..8c57bace8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7835,6 +7835,9 @@ static void P_InitPlayers(void) UINT8 i; INT32 skin = -1; + // Make sure objectplace is OFF when you first start the level! + OP_ResetObjectplace(); + // Are we forcing a character? if (gametype == GT_TUTORIAL) { @@ -7871,14 +7874,7 @@ static void P_InitPlayers(void) // followercolor can be left alone for hopefully obvious reasons } - if (!(gametyperules & GTR_CIRCUIT) && K_PodiumSequence() == false) - { - G_DoReborn(i); - } - else // gametype is race - { - G_SpawnPlayer(i); - } + G_SpawnPlayer(i); players[i].xtralife = 0; // extra lives do not ever carry over from the previous round } @@ -8559,7 +8555,7 @@ void P_PostLoadLevel(void) K_InitGrandPrixBots(); grandprixinfo.initalize = false; } - else if (grandprixinfo.wonround == true) + else { K_UpdateGrandPrixBots(); grandprixinfo.wonround = false; diff --git a/src/p_user.c b/src/p_user.c index 49d858240..389689c69 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3509,7 +3509,7 @@ boolean P_SpectatorJoinGame(player_t *player) // Pressing fire assigns you to a team that needs players if allowed. // Partial code reproduction from p_tick.c autobalance code. // a surprise tool that will help us later... - if (G_GametypeHasTeams()) + if (G_GametypeHasTeams() && player->ctfteam == 0) { INT32 z, numplayersred = 0, numplayersblue = 0;