From 1c3a898bbbd5539f666b08d085692a356501f219 Mon Sep 17 00:00:00 2001 From: CobaltBW Date: Thu, 15 Jul 2021 12:53:13 -0700 Subject: [PATCH 1/5] Fixed locked characters being visible in multiplayer select screen --- src/r_skins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_skins.c b/src/r_skins.c index c734b6001..86c0bbc54 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -242,7 +242,7 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum) // Force 3. return true; } - if (players[playernum].bot) + if (playernum != -1 && players[playernum].bot) { //Force 4. return true; From 4486ff065af8d6ad3567043af16a58a300aff041 Mon Sep 17 00:00:00 2001 From: CobaltBW Date: Thu, 15 Jul 2021 13:03:26 -0700 Subject: [PATCH 2/5] All remaining player->bot checks modified to rely on BOT_ constants --- src/p_inter.c | 54 +++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 7e43c46a8..21e3bfa3d 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -151,7 +151,7 @@ boolean P_CanPickupItem(player_t *player, boolean weapon) if (!player->mo || player->mo->health <= 0) return false; - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) { if (weapon) return false; @@ -178,7 +178,7 @@ void P_DoNightsScore(player_t *player) return; // Don't do any fancy shit for failures. dummymo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z+player->mo->height/2, MT_NIGHTSCORE); - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) player = &players[consoleplayer]; if (G_IsSpecialStage(gamemap)) // Global link count? Maybe not a good idea... @@ -630,7 +630,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // ***************************** // // Special Stage Token case MT_TOKEN: - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; P_AddPlayerScore(player, 1000); @@ -670,7 +670,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Emerald Hunt case MT_EMERHUNT: - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; if (hunt1 == special) @@ -701,7 +701,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_EMERALD5: case MT_EMERALD6: case MT_EMERALD7: - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; if (special->threshold) @@ -738,7 +738,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Secret emblem thingy case MT_EMBLEM: { - if (demoplayback || (player->bot && player->bot != 3)) + if (demoplayback || (player->bot && player->bot != BOT_MPAI)) return; emblemlocations[special->health-1].collected = true; @@ -751,7 +751,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // CTF Flags case MT_REDFLAG: case MT_BLUEFLAG: - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; if (player->powers[pw_flashing] || player->tossdelay) return; @@ -826,7 +826,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { boolean spec = G_IsSpecialStage(gamemap); boolean cangiveemmy = false; - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; if (player->exiting) return; @@ -1072,7 +1072,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } return; case MT_EGGCAPSULE: - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; // make sure everything is as it should be, THEN take rings from players in special stages @@ -1164,7 +1164,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } return; case MT_NIGHTSSUPERLOOP: - if ((player->bot && player->bot != 3) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) + if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) return; if (!G_IsSpecialStage(gamemap)) player->powers[pw_nights_superloop] = (UINT16)special->info->speed; @@ -1186,7 +1186,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } break; case MT_NIGHTSDRILLREFILL: - if ((player->bot && player->bot != 3) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) + if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) return; if (!G_IsSpecialStage(gamemap)) player->drillmeter = special->info->speed; @@ -1208,7 +1208,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } break; case MT_NIGHTSHELPER: - if ((player->bot && player->bot != 3) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) + if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) return; if (!G_IsSpecialStage(gamemap)) { @@ -1240,7 +1240,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } break; case MT_NIGHTSEXTRATIME: - if ((player->bot && player->bot != 3) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) + if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) return; if (!G_IsSpecialStage(gamemap)) { @@ -1272,7 +1272,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } break; case MT_NIGHTSLINKFREEZE: - if ((player->bot && player->bot != 3) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) + if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE)) return; if (!G_IsSpecialStage(gamemap)) { @@ -1332,7 +1332,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE) players[i].drillmeter += TICRATE/2; } - else if (player->bot && player->bot != 3) + else if (player->bot && player->bot != BOT_MPAI) players[consoleplayer].drillmeter += TICRATE/2; else player->drillmeter += TICRATE/2; @@ -1385,7 +1385,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) thinker_t *th; mobj_t *mo2; - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; // Initialize my junk @@ -1423,7 +1423,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } case MT_FIREFLOWER: - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; S_StartSound(toucher, sfx_mario3); @@ -1685,7 +1685,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // Only go in the mouth // Eaten by player! - if ((!player->bot || player->bot == 3) && (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)) + if ((!player->bot || player->bot == BOT_MPAI) && (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)) { player->powers[pw_underwater] = underwatertics + 1; P_RestoreMusic(player); @@ -1696,7 +1696,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!player->climbing) { - if (player->bot && player->bot != 3 && toucher->state-states != S_PLAY_GASP) + if (player->bot && player->bot != BOT_MPAI && toucher->state-states != S_PLAY_GASP) S_StartSound(toucher, special->info->deathsound); // Force it to play a sound for bots P_SetPlayerMobjState(toucher, S_PLAY_GASP); P_ResetPlayer(player); @@ -1704,7 +1704,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) toucher->momx = toucher->momy = toucher->momz = 0; - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; else break; @@ -1736,7 +1736,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; case MT_MINECARTSPAWNER: - if (!player->bot && player->bot != 3 && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART && !(player->powers[pw_ignorelatch] & (1<<15))) + if (!player->bot && player->bot != BOT_MPAI && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART && !(player->powers[pw_ignorelatch] & (1<<15))) { mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART); P_SetTarget(&mcart->target, toucher); @@ -1789,7 +1789,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } return; default: // SOC or script pickup - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; P_SetTarget(&special->target, toucher); break; @@ -1813,7 +1813,7 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost) mobj_t *toucher = player->mo; mobj_t *checkbase = snaptopost ? post : toucher; - if (player->bot && player->bot != 3) + if (player->bot && player->bot != BOT_MPAI) return; // In circuit, player must have touched all previous starposts if (circuitmap @@ -2555,7 +2555,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if ((target->player->lives <= 1) && (netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value == 0)) ; - else if ((!target->player->bot || target->player->bot == 3) && !target->player->spectator && (target->player->lives != INFLIVES) + else if ((!target->player->bot || target->player->bot == BOT_MPAI) && !target->player->spectator && (target->player->lives != INFLIVES) && G_GametypeUsesLives()) { if (!(target->player->pflags & PF_FINISHED)) @@ -3475,7 +3475,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) if (inflictor && inflictor->type == MT_LHRT) return; - if (player->powers[pw_shield] || (player->bot && player->bot != 3)) //If One-Hit Shield + if (player->powers[pw_shield] || (player->bot && player->bot != BOT_MPAI)) //If One-Hit Shield { P_RemoveShield(player); S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss. @@ -3566,7 +3566,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Make sure that boxes cannot be popped by enemies, red rings, etc. - if (target->flags & MF_MONITOR && ((!source || !source->player || (source->player->bot && source->player->bot != 3)) + if (target->flags & MF_MONITOR && ((!source || !source->player || (source->player->bot && source->player->bot != BOT_MPAI)) || (inflictor && (inflictor->type == MT_REDRING || (inflictor->type >= MT_THROWNBOUNCE && inflictor->type <= MT_THROWNGRENADE))))) return false; } @@ -3701,7 +3701,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } else if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype)) return true; - else if (player->powers[pw_shield] || (player->bot && player->bot != 3 && !ultimatemode)) //If One-Hit Shield + else if (player->powers[pw_shield] || (player->bot && player->bot != BOT_MPAI && !ultimatemode)) //If One-Hit Shield { P_ShieldDamage(player, inflictor, source, damage, damagetype); damage = 0; From 48514ee88d54a5d36a92c2af0fdd1feb587acf2d Mon Sep 17 00:00:00 2001 From: CobaltBW Date: Thu, 15 Jul 2021 15:04:24 -0700 Subject: [PATCH 3/5] Fixed G_RemovePlayer crash in players.iterate This was done by storing flag-for-removal status as a boolean inside the player struct. Bot players are instead removed at the start of G_Ticker, rather than being removed immediately by G_RemovePlayer. --- src/d_player.h | 1 + src/g_game.c | 22 +++++++++++++++++++++- src/lua_baselib.c | 14 ++------------ src/p_saveg.c | 2 ++ 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 89776fe5e..a0db1402d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -559,6 +559,7 @@ typedef struct player_s boolean spectator; boolean outofcoop; + boolean removing; UINT8 bot; struct player_s *botleader; UINT16 lastbuttons; diff --git a/src/g_game.c b/src/g_game.c index 0643350b6..4d501f526 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1545,7 +1545,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) cmd->forwardmove = (SINT8)(cmd->forwardmove + forward); cmd->sidemove = (SINT8)(cmd->sidemove + side); - //Note: Majority of botstuffs are handled in G_Ticker now. + // Note: Majority of botstuffs are handled in G_Ticker now. if (player->bot == BOT_2PHUMAN) //Player-controlled bot { G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver @@ -2198,6 +2198,23 @@ void G_Ticker(boolean run) UINT32 i; INT32 buf; + // Bot players queued for removal + for (i = MAXPLAYERS-1; i != UINT32_MAX; i--) + { + if (playeringame[i] && players[i].removing) + { + CL_RemovePlayer(i, i); + if (netgame) + { + char kickmsg[256]; + + strcpy(kickmsg, M_GetText("\x82*Bot %s has been removed")); + strcpy(kickmsg, va(kickmsg, player_names[i], i)); + HU_AddChatText(kickmsg, false); + } + } + } + // see also SCR_DisplayMarathonInfo if ((marathonmode & (MA_INIT|MA_INGAME)) == MA_INGAME && gamestate == GS_LEVEL) marathontime++; @@ -2520,6 +2537,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) tic_t quittime; boolean spectator; boolean outofcoop; + boolean removing; INT16 bot; SINT8 pity; INT16 rings; @@ -2536,6 +2554,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) quittime = players[player].quittime; spectator = players[player].spectator; outofcoop = players[player].outofcoop; + removing = players[player].removing; pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER)); playerangleturn = players[player].angleturn; oldrelangleturn = players[player].oldrelangleturn; @@ -2612,6 +2631,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->quittime = quittime; p->spectator = spectator; p->outofcoop = outofcoop; + p->removing = removing; p->angleturn = playerangleturn; p->oldrelangleturn = oldrelangleturn; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9946a9fd3..9e01a98c0 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3482,24 +3482,14 @@ static int lib_gAddPlayer(lua_State *L) static int lib_gRemovePlayer(lua_State *L) { UINT8 pnum = -1; - //const char *kickreason = luaL_checkstring(L, 2); if (!lua_isnoneornil(L, 1)) pnum = luaL_checkinteger(L, 1); if (&players[pnum]) { - if (players[pnum].bot != BOT_NONE) + if (players[pnum].bot != BOT_NONE && players[pnum].removing == false) { -// CL_RemovePlayer(pnum, *kickreason); - CL_RemovePlayer(pnum, pnum); - if (netgame) - { - char kickmsg[256]; - - strcpy(kickmsg, M_GetText("\x82*Bot %s has been removed")); - strcpy(kickmsg, va(kickmsg, player_names[pnum], pnum)); - HU_AddChatText(kickmsg, false); - } + players[pnum].removing = true; // This function can be run in players.iterate(), which isn't equipped to deal with players being removed mid-process. Instead we'll remove the player at the beginning of the next ticframe. lua_pushboolean(L, true); return 1; } diff --git a/src/p_saveg.c b/src/p_saveg.c index 7e9d7b6d4..1270064c0 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -201,6 +201,7 @@ static void P_NetArchivePlayers(void) WRITEUINT8(save_p, players[i].botmem.lastBlocked); WRITEUINT8(save_p, players[i].botmem.catchup_tics); WRITEUINT8(save_p, players[i].botmem.thinkstate); + WRITEUINT8(save_p, players[i].removing); WRITEUINT8(save_p, players[i].blocked); WRITEUINT16(save_p, players[i].lastbuttons); @@ -428,6 +429,7 @@ static void P_NetUnArchivePlayers(void) players[i].botmem.lastBlocked = READUINT8(save_p); players[i].botmem.catchup_tics = READUINT8(save_p); players[i].botmem.thinkstate = READUINT8(save_p); + players[i].removing = READUINT8(save_p); players[i].blocked = READUINT8(save_p); players[i].lastbuttons = READUINT16(save_p); From 22f42efb61e242a75a017712d6b753149c3a91ce Mon Sep 17 00:00:00 2001 From: CobaltBW Date: Thu, 15 Jul 2021 15:09:02 -0700 Subject: [PATCH 4/5] Cleaned up leftover comments --- src/b_bot.c | 4 ---- src/g_game.c | 2 +- src/p_mobj.c | 1 - src/p_user.c | 29 ++++++----------------------- 4 files changed, 7 insertions(+), 29 deletions(-) diff --git a/src/b_bot.c b/src/b_bot.c index c61e56f5f..6f4b0ce15 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -102,7 +102,6 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) if (tails->player->powers[pw_carry] == CR_MACESPIN || tails->player->powers[pw_carry] == CR_GENERIC) { boolean isrelevant = (sonic->player->powers[pw_carry] == CR_MACESPIN || sonic->player->powers[pw_carry] == CR_GENERIC); - //dist = P_AproxDistance(tails->x-sonic->x, tails->y-sonic->y); //! This is totally redundant. if (sonic->player->cmd.buttons & BT_JUMP && (sonic->player->pflags & PF_JUMPED) && isrelevant) cmd->buttons |= BT_JUMP; if (isrelevant) @@ -402,8 +401,6 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward { player_t *player = mo->player; // don't try to do stuff if your sonic is in a minecart or something - //if (players[consoleplayer].powers[pw_carry] && players[consoleplayer].powers[pw_carry] != CR_PLAYER) - //!!! if (&player->botleader && player->botleader->powers[pw_carry] && player->botleader->powers[pw_carry] != CR_PLAYER) return; // Turn the virtual keypresses into ticcmd_t. @@ -576,7 +573,6 @@ void B_RespawnBot(INT32 playernum) player->powers[pw_spacetime] = sonic->player->powers[pw_spacetime]; player->powers[pw_gravityboots] = sonic->player->powers[pw_gravityboots]; player->powers[pw_nocontrol] = sonic->player->powers[pw_nocontrol]; - //!!! Nuke the speed equivalencies player->pflags |= PF_AUTOBRAKE|(sonic->player->pflags & PF_DIRECTIONCHAR); P_TeleportMove(tails, x, y, z); diff --git a/src/g_game.c b/src/g_game.c index 4d501f526..8cdeaf079 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3025,7 +3025,7 @@ void G_DoReborn(INT32 playernum) // Make sure objectplace is OFF when you first start the level! OP_ResetObjectplace(); - //! Tailsbot + // Tailsbot if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) { // Bots respawn next to their master. mobj_t *oldmo = NULL; diff --git a/src/p_mobj.c b/src/p_mobj.c index 4924ec053..8af7ab0d0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1839,7 +1839,6 @@ void P_XYMovement(mobj_t *mo) // blocked move moved = false; - //!!! if (player) B_MoveBlocked(player); diff --git a/src/p_user.c b/src/p_user.c index dadc23193..b3535623c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -776,7 +776,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) { UINT8 oldmare, oldmarelap, oldmarebonuslap; - //! Bots can't be NiGHTSerized, silly!1 :P + // Bots can't be NiGHTSerized, silly!1 :P if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) return; @@ -1188,7 +1188,7 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) { if (!player) return; - //! + if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader) player = player->botleader; @@ -5965,23 +5965,6 @@ static void P_3dMovement(player_t *player) acceleration = 96 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * 40; topspeed = normalspd; } - //! Kill this! - /* else if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) - { // Bot steals player 1's stats - normalspd = FixedMul(players[consoleplayer].normalspeed, player->mo->scale); - thrustfactor = players[consoleplayer].thrustfactor; - acceleration = players[consoleplayer].accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * players[consoleplayer].acceleration; - - if (player->powers[pw_tailsfly]) - topspeed = normalspd/2; - else if (player->mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER)) - { - topspeed = normalspd/2; - acceleration = 2*acceleration/3; - } - else - topspeed = normalspd; - } */ else { if (player->powers[pw_super] || player->powers[pw_sneakers]) @@ -11488,7 +11471,7 @@ void P_PlayerThink(player_t *player) I_Error("p_playerthink: players[%s].mo == NULL", sizeu1(playeri)); #endif - //! Reset terrain blocked status for this frame + // Reset terrain blocked status for this frame player->blocked = false; // todo: Figure out what is actually causing these problems in the first place... @@ -11641,7 +11624,7 @@ void P_PlayerThink(player_t *player) INT32 i; for (i = 0; i < MAXPLAYERS; i++) - { //! + { if (!playeringame[i] || players[i].spectator || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN) continue; if (players[i].lives <= 0) @@ -11673,7 +11656,7 @@ void P_PlayerThink(player_t *player) INT32 i, total = 0, exiting = 0; for (i = 0; i < MAXPLAYERS; i++) - { //! + { if (!playeringame[i] || players[i].spectator || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN) continue; if (players[i].quittime > 30 * TICRATE) @@ -12614,7 +12597,7 @@ void P_PlayerAfterThink(player_t *player) player->mo->momy = tails->momy; player->mo->momz = tails->momz; } - //! + if (G_CoopGametype() && tails->player && tails->player->bot != BOT_2PAI) { player->mo->angle = tails->angle; From 95359fef5142d1dce33ebce35b18d13846e2ca56 Mon Sep 17 00:00:00 2001 From: CobaltBW Date: Thu, 15 Jul 2021 15:19:47 -0700 Subject: [PATCH 5/5] Amendment to G_RemovePlayer to preserve lua error handlers --- src/lua_baselib.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9e01a98c0..f287fb78c 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3482,20 +3482,25 @@ static int lib_gAddPlayer(lua_State *L) static int lib_gRemovePlayer(lua_State *L) { UINT8 pnum = -1; - if (!lua_isnoneornil(L, 1)) pnum = luaL_checkinteger(L, 1); - if (&players[pnum]) + else // No argument + return luaL_error(L, "argument #1 not given (expected number)"); + if (pnum >= MAXPLAYERS) // Out of range + return luaL_error(L, "playernum %d out of range (0 - %d)", pnum, MAXPLAYERS-1); + if (playeringame[pnum]) // Found player { - if (players[pnum].bot != BOT_NONE && players[pnum].removing == false) + if (players[pnum].bot == BOT_NONE) // Can't remove clients. + return luaL_error(L, "G_RemovePlayer can only be used on players with a bot value other than BOT_NONE."); + else { - players[pnum].removing = true; // This function can be run in players.iterate(), which isn't equipped to deal with players being removed mid-process. Instead we'll remove the player at the beginning of the next ticframe. + players[pnum].removing = true; lua_pushboolean(L, true); return 1; } } - lua_pushboolean(L, false); - return 1; + // Fell through. Invalid player + return LUA_ErrInvalid(L, "player_t"); }