From 71f9b79e717b35d625e8273b783c6ca1dcaafdeb Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 20 Aug 2023 18:20:46 -0700 Subject: [PATCH 1/5] Prisons: fix exit conditions around spectating Fixes player death not ending a Prisons round, bugged debug feature. Now, do it properly. Don't end the round if the last player spectates. This is more than a debug feature; in Free Play, it lets the player spectate and fly around if they want to, and even come back in, all without restarting the level. --- src/k_battle.c | 7 ++----- src/p_inter.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 6 deletions(-) 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/p_inter.c b/src/p_inter.c index 890644320..b68ee18dd 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; @@ -2160,6 +2164,12 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, player->pflags |= PF_ELIMINATED; } + if (type == DMG_SPECTATOR) + { + // Set it here so K_CheckBumpers knows about it later. + player->spectator = true; + } + return true; } From e123ed7480ef733e2c48d7093c0448c0476e653d Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 26 Aug 2023 19:48:20 +0100 Subject: [PATCH 2/5] MAJOR cleanup of Spectator set/unset - G_AddPlayer now contains CL_ClearPlayer, G_DestroyParty, and playeringame set - Instead of a nasty, complicated block in P_SpawnPlayer, externalise it into G_SpectatePlayerOnJoin - All mid-game human player-to-spectator transitions are handled by P_SetPlayerSpectator, instead of lots of `spectator = true` and associated boilerplate - Simplifies Got_Teamchange MASSIVELY - Of course this is helped by also stripping back team change - This is called by P_KillPlayer, too - P_KillPlayer no longer eats DMG_SPECTATOR when lightsnaking or exiting - G_GametypeHasSpectators condition tidied --- src/d_clisrv.c | 16 ++------ src/d_netcmd.c | 99 ++++++++++++++++++++--------------------------- src/d_netcmd.h | 1 + src/g_demo.c | 39 ++++++++++--------- src/g_demo.h | 2 + src/g_game.c | 50 ++++++++++++++++++++++-- src/g_game.h | 1 + src/k_bot.c | 6 +-- src/k_grandprix.c | 2 +- src/p_inter.c | 41 ++++++++------------ src/p_mobj.c | 75 +++++------------------------------ src/p_user.c | 2 +- 12 files changed, 146 insertions(+), 188 deletions(-) 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 e5e3e267f..5ca7f30cf 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1189,14 +1189,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); + } } } } @@ -3448,6 +3447,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) { @@ -3519,55 +3534,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) @@ -3595,20 +3593,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 345b65d95..98f823a18 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2822,11 +2822,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) @@ -3245,7 +3287,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 84dc5f4ac..8b1ae5b9f 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -239,6 +239,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_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..65a8e3acd 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? } } } diff --git a/src/p_inter.c b/src/p_inter.c index b68ee18dd..4cb50bd7a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2056,30 +2056,29 @@ 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) + { + K_DoInstashield(player); + return false; + } + + if (player->exiting) + { + player->mo->destscale = 1; + player->mo->flags |= MF_NOCLIPTHING; + return false; + } + + if (specialstageinfo.valid == true || (modeattacking & ATTACKING_SPB)) { P_DoPlayerExit(player, PF_NOCONTEST); } -#else - P_DoPlayerExit(player, PF_NOCONTEST); -#endif - } - - if (player->exiting) - { - player->mo->destscale = 1; - player->mo->flags |= MF_NOCLIPTHING; - return false; } switch (type) @@ -2164,12 +2163,6 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, player->pflags |= PF_ELIMINATED; } - if (type == DMG_SPECTATOR) - { - // Set it here so K_CheckBumpers knows about it later. - player->spectator = true; - } - return true; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 1e6a797d1..e1090bf33 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11770,61 +11770,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; @@ -11834,9 +11797,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; @@ -11845,22 +11805,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. @@ -11959,8 +11903,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_user.c b/src/p_user.c index a5176e580..d31977e8d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3504,7 +3504,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; From 67c2ae021bff62709b16e58ff20cd6e24fed32aa Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 27 Aug 2023 16:00:39 -0700 Subject: [PATCH 3/5] P_SpawnPlayer: add back explicit spectator handling for bots; also remove it from k_grandprix.c Not needed in K_UpdateGrandPrixBots or K_LoadGrandPrixSaveGame because P_SpawnPlayer takes priority. --- src/k_grandprix.c | 12 ------------ src/p_mobj.c | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/k_grandprix.c b/src/k_grandprix.c index 65a8e3acd..f65e7aec3 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -307,8 +307,6 @@ void K_LoadGrandPrixSaveGame(void) players[i].botvars.rival = savedata.bots[i].rival; players[i].score = savedata.bots[i].score; - - players[i].spectator = !(gametyperules & GTR_BOTS) || (grandprixinfo.eventmode != GPEVENT_NONE); } } @@ -381,16 +379,6 @@ void K_UpdateGrandPrixBots(void) return; } - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || !players[i].bot) - { - continue; - } - - players[i].spectator = !(gametyperules & GTR_BOTS) || (grandprixinfo.eventmode != GPEVENT_NONE); - } - // Find the rival. for (i = 0; i < MAXPLAYERS; i++) { diff --git a/src/p_mobj.c b/src/p_mobj.c index e1090bf33..81ebeb814 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11784,6 +11784,24 @@ void P_SpawnPlayer(INT32 playernum) if (justjoined) G_SpectatePlayerOnJoin(playernum); + if (p->bot && !demo.playback) // Don't mess with spectator values since the demo setup handles them already. + { + 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; + } + } + if (G_GametypeHasTeams()) { // If you're in a team game and you don't have a team assigned yet... From 1dd2e7031a7aeaaa7ae9958c8a1811c6570979ea Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 31 Aug 2023 16:46:46 +0100 Subject: [PATCH 4/5] Fix the spectating bots in GP issue a different way The solution in 67c2ae021bff62709b16e58ff20cd6e24fed32aa happens too late for K_TimeAttackRules --- src/k_grandprix.c | 17 +++++++++++++++++ src/p_mobj.c | 18 ------------------ src/p_setup.c | 2 +- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/k_grandprix.c b/src/k_grandprix.c index f65e7aec3..e4ab54aab 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -307,6 +307,8 @@ void K_LoadGrandPrixSaveGame(void) players[i].botvars.rival = savedata.bots[i].rival; players[i].score = savedata.bots[i].score; + + players[i].spectator = !(gametyperules & GTR_BOTS) || (grandprixinfo.eventmode != GPEVENT_NONE); } } @@ -379,6 +381,21 @@ void K_UpdateGrandPrixBots(void) return; } + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || !players[i].bot) + { + continue; + } + + 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_mobj.c b/src/p_mobj.c index 39a4c7de8..f9763afb5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11801,24 +11801,6 @@ void P_SpawnPlayer(INT32 playernum) if (justjoined) G_SpectatePlayerOnJoin(playernum); - if (p->bot && !demo.playback) // Don't mess with spectator values since the demo setup handles them already. - { - 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; - } - } - if (G_GametypeHasTeams()) { // If you're in a team game and you don't have a team assigned yet... diff --git a/src/p_setup.c b/src/p_setup.c index e9281f11b..e205bad70 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8559,7 +8559,7 @@ void P_PostLoadLevel(void) K_InitGrandPrixBots(); grandprixinfo.initalize = false; } - else if (grandprixinfo.wonround == true) + else { K_UpdateGrandPrixBots(); grandprixinfo.wonround = false; From a7b065c4d8ea1df9f22679ba8389d8e30bdbcb6d Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 31 Aug 2023 17:30:05 +0100 Subject: [PATCH 5/5] P_InitPlayers: Tidy up the barely-significant difference between G_DoReborn and G_SpawnPlayer Only kills objectplace at map start, not general respawn --- src/g_game.c | 3 --- src/p_setup.c | 12 ++++-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 9dab1231a..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; diff --git a/src/p_setup.c b/src/p_setup.c index e205bad70..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 }