diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index 48a16fdc8..4017752b5 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -350,10 +350,13 @@ ACSVM::Word Environment::callSpecImpl activator_t *activator = static_cast(Z_Calloc(sizeof(activator_t), PU_LEVEL, nullptr)); auto __ = srb2::finally( - [activator]() + [info, activator]() { - P_SetTarget(&activator->mo, NULL); - Z_Free(activator); + if (info->thread_era == thinker_era) + { + P_SetTarget(&activator->mo, NULL); + Z_Free(activator); + } } ); diff --git a/src/acs/thread.hpp b/src/acs/thread.hpp index 0b20271af..f72aac34f 100644 --- a/src/acs/thread.hpp +++ b/src/acs/thread.hpp @@ -59,6 +59,7 @@ enum acs_tagType_e class ThreadInfo : public ACSVM::ThreadInfo { public: + UINT32 thread_era; // If equal to thinker_era, mobj pointers are safe. mobj_t *mo; // Object that activated this thread. line_t *line; // Linedef that activated this thread. UINT8 side; // Front / back side of said linedef. @@ -67,6 +68,7 @@ public: bool fromLineSpecial; // Called from P_ProcessLineSpecial. ThreadInfo() : + thread_era { thinker_era }, mo{ nullptr }, line{ nullptr }, side{ 0 }, @@ -77,6 +79,7 @@ public: } ThreadInfo(const ThreadInfo &info) : + thread_era { thinker_era }, mo{ nullptr }, line{ info.line }, side{ info.side }, @@ -88,6 +91,7 @@ public: } ThreadInfo(const activator_t *activator) : + thread_era { thinker_era }, mo{ nullptr }, line{ activator->line }, side{ activator->side }, @@ -100,11 +104,15 @@ public: ~ThreadInfo() { - P_SetTarget(&mo, nullptr); + if (thread_era == thinker_era) + { + P_SetTarget(&mo, nullptr); + } } ThreadInfo &operator = (const ThreadInfo &info) { + thread_era = thinker_era; P_SetTarget(&mo, info.mo); line = info.line; side = info.side; diff --git a/src/p_local.h b/src/p_local.h index fccc0287f..1e5eee012 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -79,6 +79,7 @@ typedef enum extern thinker_t thlist[]; void P_InitThinkers(void); +void P_InvalidateThinkersWithoutInit(void); void P_AddThinker(const thinklistnum_t n, thinker_t *thinker); void P_RemoveThinker(thinker_t *thinker); void P_UnlinkThinker(thinker_t *thinker); diff --git a/src/p_tick.c b/src/p_tick.c index 1ad1c8dd2..98ca4b690 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -53,6 +53,8 @@ tic_t leveltime; boolean thinkersCompleted; +UINT32 thinker_era = 0; + static boolean g_freezeCheat; static boolean g_freezeLevel; @@ -276,6 +278,8 @@ void P_InitThinkers(void) { UINT8 i; + P_InvalidateThinkersWithoutInit(); + for (i = 0; i < NUM_THINKERLISTS; i++) { thlist[i].prev = thlist[i].next = &thlist[i]; @@ -297,6 +301,15 @@ void P_InitThinkers(void) Obj_ResetCheckpoints(); } +// +// P_InvalidateThinkersWithoutInit +// + +void P_InvalidateThinkersWithoutInit(void) +{ + thinker_era++; +} + // Adds a new thinker at the end of the list. void P_AddThinker(const thinklistnum_t n, thinker_t *thinker) { diff --git a/src/p_tick.h b/src/p_tick.h index 58c154a1a..ab36c2e51 100644 --- a/src/p_tick.h +++ b/src/p_tick.h @@ -43,6 +43,8 @@ void P_PreTicker(INT32 frames); void P_DoTeamscrambling(void); void P_RemoveThinkerDelayed(thinker_t *thinker); //killed +extern UINT32 thinker_era; + mobj_t *P_SetTarget2(mobj_t **mo, mobj_t *target #ifdef PARANOIA , const char *source_file, int source_line