From 44b642ffa38bdc851a3d805e8751deb9f7e2eb55 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 10 Apr 2023 22:39:17 -0700 Subject: [PATCH 01/17] WIP: improved countersteering --- src/k_kart.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index c06b15bd7..5fcaa2ca1 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8854,10 +8854,17 @@ INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering) // player->steering is the turning value, but with easing applied. // Keeps micro-turning from old easing, but isn't controller dependent. - const INT16 amount = KART_FULLTURN/3; + INT16 amount = KART_FULLTURN/3; INT16 diff = destSteering - inputSteering; INT16 outputSteering = inputSteering; + + if ((inputSteering > 0 && destSteering < inputSteering) || (inputSteering < 0 && destSteering > inputSteering)) + { + amount = KART_FULLTURN; + } + + if (abs(diff) <= amount) { // Reached the intended value, set instantly. From 94cf9fc47bc0c15bcdadf1e0f99a83d1e6e5070e Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 10 Apr 2023 23:15:23 -0700 Subject: [PATCH 02/17] WIP: don't oversteer when crossing 0 boundary --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 5fcaa2ca1..cdce66665 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8859,9 +8859,9 @@ INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering) INT16 outputSteering = inputSteering; - if ((inputSteering > 0 && destSteering < inputSteering) || (inputSteering < 0 && destSteering > inputSteering)) + if ((inputSteering > 0 && destSteering < 0) || (inputSteering < 0 && destSteering > 0)) { - amount = KART_FULLTURN; + amount = max(min(KART_FULLTURN, abs(inputSteering)), amount); } From b4ffc33fcb56034b339cb65603ad30c43203fda2 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Tue, 11 Apr 2023 00:15:44 -0700 Subject: [PATCH 03/17] Sliptide-aware camera steering, fix countersteer easing --- src/k_kart.c | 6 +++++- src/p_user.c | 22 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index cdce66665..43ebdea3a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8859,9 +8859,13 @@ INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering) INT16 outputSteering = inputSteering; + // We switched steering directions, lighten up on easing for a more responsive countersteer. + // (Don't do this for steering 0, let digital inputs tap-adjust!) if ((inputSteering > 0 && destSteering < 0) || (inputSteering < 0 && destSteering > 0)) { - amount = max(min(KART_FULLTURN, abs(inputSteering)), amount); + // Don't let small turns in direction X allow instant turns in direction Y. + INT16 countersteer = min(KART_FULLTURN, abs(inputSteering)); // The farthest we should go is to 0 -- neutral. + amount = max(countersteer, amount); // But don't reduce turning strength from baseline either. } diff --git a/src/p_user.c b/src/p_user.c index e05d1a0f7..b48dc206d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2235,16 +2235,30 @@ static void P_UpdatePlayerAngle(player_t *player) angle_t leniency = (4*ANG1/3) * min(player->cmd.latency, 6); // Don't force another turning tic, just give them the desired angle! - if (targetDelta == angleChange || K_Sliptiding(player) || (maxTurnRight == 0 && maxTurnLeft == 0)) + if (targetDelta == angleChange || (maxTurnRight == 0 && maxTurnLeft == 0)) { - // Either we're dead on, we can't steer, or we're in a special handling state. - // Stuff like sliptiding requires some blind-faith steering: - // if a camera correction stops our turn input, the sliptide randomly fails! + // Either we're dead on or we can't steer at all. player->steering = targetsteering; } else { // We're off. Try to legally steer the player towards their camera. + + if (K_Sliptiding(player) && P_IsObjectOnGround(player->mo) && (player->cmd.turning != 0) && ((player->cmd.turning > 0) == (player->aizdriftstrat > 0))) + { + // Don't change handling direction if someone's inputs are sliptiding, you'll break the sliptide! + if (player->cmd.turning > 0) + { + steeringRight = max(steeringRight, max(steeringLeft, 1)); + steeringLeft = max(steeringLeft, 1); + } + else + { + steeringLeft = min(steeringLeft, max(steeringRight, -1)); + steeringRight = min(steeringLeft, -1); + } + } + player->steering = P_FindClosestTurningForAngle(player, targetDelta, steeringLeft, steeringRight); angleChange = K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE; From b9133530e2ed52ae5100f1e07091e5f4b2880049 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 11 Apr 2023 17:39:53 +0100 Subject: [PATCH 04/17] Obj_OrbinautJawzCollide: Guard for removed objects --- src/objects/orbinaut.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/objects/orbinaut.c b/src/objects/orbinaut.c index caed22068..f7c2ac89a 100644 --- a/src/objects/orbinaut.c +++ b/src/objects/orbinaut.c @@ -260,14 +260,25 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) damageitem = false; } - if (damageitem) + if (damageitem && P_MobjWasRemoved(t1) == false) { + angle_t bounceangle; + if (P_MobjWasRemoved(t2) == false) + { + bounceangle = K_GetCollideAngle(t2, t1); + } + else + { + bounceangle = K_MomentumAngle(t1) + ANGLE_90; + t2 = NULL; // handles the arguments to P_KillMobj + } + // This Item Damage - angle_t bounceangle = K_GetCollideAngle(t2, t1); S_StartSound(t1, t1->info->deathsound); P_KillMobj(t1, t2, t2, DMG_NORMAL); P_SetObjectMomZ(t1, 24*FRACUNIT, false); + P_InstaThrust(t1, bounceangle, 16*FRACUNIT); } From c7e510a3ece25ec0558c2da05b58a3be321406c4 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 11 Apr 2023 17:41:41 +0100 Subject: [PATCH 05/17] k_collide.cpp: Guard against dereferencing possibly invalid t2 --- src/k_collide.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 671f3d19a..9bb2283be 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -444,15 +444,22 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) else t2->z += t2->height; + P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH); + S_StartSound(t2, t2->info->deathsound); P_KillMobj(t2, t1, t1, DMG_NORMAL); - P_SetObjectMomZ(t2, 24*FRACUNIT, false); - P_InstaThrust(t2, bounceangle, 16*FRACUNIT); + if (P_MobjWasRemoved(t2)) + { + t2 = NULL; // handles the arguments to P_KillMobj + } + else + { + P_SetObjectMomZ(t2, 24*FRACUNIT, false); + P_InstaThrust(t2, bounceangle, 16*FRACUNIT); - P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH); - - t1->reactiontime = t2->hitlag; + t1->reactiontime = t2->hitlag; + } P_KillMobj(t1, t2, t2, DMG_NORMAL); } else if (t2->type == MT_SSMINE_SHIELD || t2->type == MT_SSMINE || t2->type == MT_LANDMINE) @@ -466,7 +473,15 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2) // Shootable damage P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL); - t1->reactiontime = t2->hitlag; + if (P_MobjWasRemoved(t2)) + { + t2 = NULL; // handles the arguments to P_KillMobj + } + else + { + t1->reactiontime = t2->hitlag; + } + P_KillMobj(t1, t2, t2, DMG_NORMAL); } @@ -796,6 +811,10 @@ boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2) { // Shootable damage P_KillMobj(t2, t2, t1->target, DMG_NORMAL); + if (P_MobjWasRemoved(t2)) + { + t2 = NULL; // handles the arguments to P_KillMobj + } // This item damage P_KillMobj(t1, t2, t2, DMG_NORMAL); } From 1a2121b3ca895257ab798ba737a5b3f09e4162d2 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 11 Apr 2023 20:32:55 -0700 Subject: [PATCH 06/17] K_ProcessTerrainEffect: fix spring crash on top of FOF --- src/k_terrain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_terrain.c b/src/k_terrain.c index 0bf90fc17..d0f3d52bf 100644 --- a/src/k_terrain.c +++ b/src/k_terrain.c @@ -584,7 +584,7 @@ void K_ProcessTerrainEffect(mobj_t *mo) { if (player->mo->floorrover != NULL) { - slope = *player->mo->ceilingrover->t_slope; + slope = *player->mo->floorrover->t_slope; } else { From d870bf0416602e650ed824922358bcbbab4fa2ab Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Wed, 12 Apr 2023 00:47:00 -0700 Subject: [PATCH 07/17] Fix min/max allowing for theoretical handling breakage in camera-sliptide logic --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index b48dc206d..d58ac8c26 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2254,7 +2254,7 @@ static void P_UpdatePlayerAngle(player_t *player) } else { - steeringLeft = min(steeringLeft, max(steeringRight, -1)); + steeringLeft = min(steeringLeft, min(steeringRight, -1)); steeringRight = min(steeringLeft, -1); } } From e3ea9df6833f3c7be0f66007a26d29c6aa351a48 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Wed, 12 Apr 2023 01:26:33 -0700 Subject: [PATCH 08/17] Fix sliptide death-spirals on input boundary cross --- src/p_user.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index d58ac8c26..631df9583 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2249,13 +2249,13 @@ static void P_UpdatePlayerAngle(player_t *player) // Don't change handling direction if someone's inputs are sliptiding, you'll break the sliptide! if (player->cmd.turning > 0) { - steeringRight = max(steeringRight, max(steeringLeft, 1)); steeringLeft = max(steeringLeft, 1); + steeringRight = max(steeringRight, steeringLeft); } else { - steeringLeft = min(steeringLeft, min(steeringRight, -1)); - steeringRight = min(steeringLeft, -1); + steeringRight = min(steeringRight, -1); + steeringLeft = min(steeringLeft, steeringRight); } } From adc2adb5c8b21c7f9466c685b94d9a9073befa0a Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 12 Apr 2023 14:54:42 +0100 Subject: [PATCH 09/17] I_ShowErrorMessageBox for SDL interface Handles showing the error message box on quit. - Polite communication that the game fell over and that you (probably) didn't do anything wrong - Accomodates pointing you to UNIXBACKTRACE and _WIN32 exchndl crash logs if relevant - Points you to the specific dated and timed log file that contains the error - Tells you that the vague and often confusing error message (like I_Error) is for a programmer, server host, or add-on creator - Hee Ho! --- src/sdl/i_system.c | 114 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 97 insertions(+), 17 deletions(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 76cafa09a..f6b2853ab 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -268,6 +268,93 @@ static void write_backtrace(INT32 signal) #undef CRASHLOG_STDERR_WRITE #endif // UNIXBACKTRACE +static void I_ShowErrorMessageBox(const char *messagefordevelopers, boolean dumpmade) +{ + static char finalmessage[1024]; + size_t firstimpressionsline = 3; // "Dr Robotnik's Ring Racers" has encountered... + + if (M_CheckParm("-dedicated")) + return; + + snprintf( + finalmessage, + sizeof(finalmessage), + "Hee Ho!\n" + "\n" + "\"Dr. Robotnik's Ring Racers\" has encountered an unrecoverable error and needs to close.\n" + "This is (usually) not your fault, but we encourage you to report it in the community. This should be done alongside your " + "%s" + "log file (%s).\n" + "\n" + "The following information is for a programmer (please be nice to them!) but\n" + "may also be useful for server hosts and add-on creators.\n" + "\n" + "%s", + dumpmade ? +#if defined (UNIXBACKTRACE) + "crash-log.txt" +#elif defined (_WIN32) + ".rpt crash dump" +#endif + " (very important!) and " : "", + logfilename, + messagefordevelopers); + + // Rudementary word wrapping. + // Simple and effective. Does not handle nonuniform letter sizes, etc. but who cares. + { + size_t max = 0, maxatstart = 0, start = 0, width = 0, i; + + for (i = 0; finalmessage[i]; i++) + { + if (finalmessage[i] == ' ') + { + start = i; + max += 4; + maxatstart = max; + } + else if (finalmessage[i] == '\n') + { + if (firstimpressionsline > 0) + { + firstimpressionsline--; + if (firstimpressionsline == 0) + { + width = max; + } + } + start = 0; + max = 0; + maxatstart = 0; + continue; + } + else + max += 8; + + // Start trying to wrap if presumed length exceeds the space we want. + if (width > 0 && max >= width && start > 0) + { + finalmessage[start] = '\n'; + max -= maxatstart; + start = 0; + } + } + } + + // Implement message box with SDL_ShowSimpleMessageBox, + // which should fail gracefully if it can't put a message box up + // on the target system + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + "Dr. Robotnik's Ring Racers "VERSIONSTRING" Error", + finalmessage, NULL); + + // Note that SDL_ShowSimpleMessageBox does *not* require SDL to be + // initialized at the time, so calling it after SDL_Quit() is + // perfectly okay! In addition, we do this on purpose so the + // fullscreen window is closed before displaying the error message + // in case the fullscreen window blocks it for some absurd reason. +} + static void I_ReportSignal(int num, int coredumped) { //static char msg[] = "oh no! back to reality!\r\n"; @@ -317,10 +404,15 @@ static void I_ReportSignal(int num, int coredumped) I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg); - if (!M_CheckParm("-dedicated")) - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "Process killed by signal", - sigmsg, NULL); + I_ShowErrorMessageBox(sigmsg, +#if defined (UNIXBACKTRACE) + true +#elif defined (_WIN32) + !M_CheckParm("-noexchndl") +#else + false +#endif + ); } #ifndef NEWSIGNALHANDLER @@ -1712,13 +1804,7 @@ void I_Error(const char *error, ...) I_ShutdownGraphics(); I_ShutdownInput(); - // Implement message box with SDL_ShowSimpleMessageBox, - // which should fail gracefully if it can't put a message box up - // on the target system - if (!M_CheckParm("-dedicated")) - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "Dr. Robotnik's Ring Racers "VERSIONSTRING" Error", - buffer, NULL); + I_ShowErrorMessageBox(buffer, false); // We wait until now to do this so the funny sound can be heard I_ShutdownSound(); @@ -1726,12 +1812,6 @@ void I_Error(const char *error, ...) I_ShutdownSystem(); SDL_Quit(); - // Note that SDL_ShowSimpleMessageBox does *not* require SDL to be - // initialized at the time, so calling it after SDL_Quit() is - // perfectly okay! In addition, we do this on purpose so the - // fullscreen window is closed before displaying the error message - // in case the fullscreen window blocks it for some absurd reason. - W_Shutdown(); #if defined (PARANOIA) || defined (DEVELOP) From 74247d8100fb55007b091e096a79737362d843f6 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 12 Apr 2023 15:08:17 +0100 Subject: [PATCH 10/17] Permit compiling with LOGMESSAGES disabled (and accomodate a crash early enough in the startup before the log is made, too) --- src/sdl/i_system.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index f6b2853ab..f93a3b3b4 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -297,7 +297,10 @@ static void I_ShowErrorMessageBox(const char *messagefordevelopers, boolean dump ".rpt crash dump" #endif " (very important!) and " : "", - logfilename, +#ifdef LOGMESSAGES + logfilename[0] ? logfilename : +#endif + "uh oh, one wasn't made!?", messagefordevelopers); // Rudementary word wrapping. From 8311ba8acbd0b854fa6454f8f44f21dd5695ffd1 Mon Sep 17 00:00:00 2001 From: SteelT Date: Wed, 12 Apr 2023 14:11:23 -0400 Subject: [PATCH 11/17] m_perfstats.c: Fix directive output may be truncated warning/error Lets the game build on my end with ERRORMODE enabled --- src/m_perfstats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_perfstats.c b/src/m_perfstats.c index f3e92fe30..75d43fc50 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -490,7 +490,7 @@ static void M_DrawTickStats(void) void M_DrawPerfStats(void) { - char s[100]; + char s[363]; PS_SetFrameTime(); From bdfccb4478b3d0fa9d64342a67be4517274fcd68 Mon Sep 17 00:00:00 2001 From: SteelT Date: Wed, 12 Apr 2023 14:31:50 -0400 Subject: [PATCH 12/17] Change static buffer size to 2048, fixes the "directive output may be truncated writing up to" error --- src/sdl/i_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index f93a3b3b4..47a2c8412 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -270,7 +270,7 @@ static void write_backtrace(INT32 signal) static void I_ShowErrorMessageBox(const char *messagefordevelopers, boolean dumpmade) { - static char finalmessage[1024]; + static char finalmessage[2048]; size_t firstimpressionsline = 3; // "Dr Robotnik's Ring Racers" has encountered... if (M_CheckParm("-dedicated")) From 43b1686abf8cb2c4f359415abf3474a32df9f029 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 12 Apr 2023 23:08:50 +0100 Subject: [PATCH 13/17] Controller rumble if Stairjank is affecting your momentum directioning Uses the same strength as offroad because of how it's functionally equivalent in Sealed Star stages --- src/p_tick.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_tick.c b/src/p_tick.c index fd24f37e4..b7e907e6b 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -782,7 +782,8 @@ void P_Ticker(boolean run) low = 65536 / (3+player->numsneakers); high = 65536 / (3+player->numsneakers); } - else if (player->boostpower < FRACUNIT && P_IsObjectOnGround(player->mo)) + else if (((player->boostpower < FRACUNIT) || (player->stairjank > 8)) + && P_IsObjectOnGround(player->mo)) { low = 65536 / 32; high = 65536 / 32; From 32d59372d32f15bcc549d8c7472b57e16a0d2fd7 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 13 Apr 2023 20:39:40 +0100 Subject: [PATCH 14/17] P_NetUnArchiveThinkers: set thinker references to 0 before removing Fixes failed assertion on server join (resolves #514) --- src/p_saveg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_saveg.c b/src/p_saveg.c index d66ea3f20..c31161f40 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4337,6 +4337,8 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save) { next = currentthinker->next; + currentthinker->references = 0; // Heinous but this is the only place the assertion in P_UnlinkThinkers is wrong + if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker || currentthinker->function.acp1 == (actionf_p1)P_NullPrecipThinker) P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it else From f3d062e4e1d3f68b532f1c5630d45e46880dc3a7 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 13 Apr 2023 16:19:35 -0700 Subject: [PATCH 15/17] Use non-DEVELOP admin promotion in (HOST)TESTERS --- src/d_netcmd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 27cdc9042..141a5341a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3919,10 +3919,7 @@ static void Command_Login_f(void) boolean IsPlayerAdmin(INT32 playernum) { -#if defined (TESTERS) || defined (HOSTTESTERS) - (void)playernum; - return false; -#elif defined (DEVELOP) +#if defined(DEVELOP) && !(defined(HOSTTESTERS) || defined(TESTERS)) return playernum != serverplayer; #else INT32 i; From 733ed325da75dd7a06eb8400956a3a20594aa72b Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 13 Apr 2023 23:28:35 -0700 Subject: [PATCH 16/17] Instead of detonating lightning when getting hit, make a sad sound --- src/k_kart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index a339b64a3..c9a66d8d6 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6164,7 +6164,8 @@ void K_PopPlayerShield(player_t *player) return; // everything is handled by Obj_GardenTopDestroy case KSHIELD_LIGHTNING: - K_DoLightningShield(player); + S_StartSound(player->mo, sfx_s3k7c); + // K_DoLightningShield(player); break; } From 2f6366938511991843c715d05f2f9b9ecd711711 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 14 Apr 2023 14:38:32 +0100 Subject: [PATCH 17/17] P_CheckPosition: If thing was removed in its remit and iteration has MF_NOCLIP, do not return true This fixes increment_move in the case of Lightning shield pop --- src/p_map.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index ed83fd441..62739d935 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2232,7 +2232,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re // with MF_NOCLIP enabled, but they won't be blocked // regardless of the result. This allows for SPBs and // the UFO to collide. - return true; + // ...but be careful about removed obj! ~toast 140423 + return !P_MobjWasRemoved(thing); } validcount++;