diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index a1730c7cef..f49da99836 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2757,11 +2757,63 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi actor->flags &= ~MF_INCHASE; } +//========================================================================== +// +// CanResurrect +// +// Checks if an actor can resurrect with another one, calling virtual script +// functions to check. +// +//========================================================================== +// [MC] Code is almost a duplicate of CanCollideWith but with changes to +// accommodate checking of just one actor. +bool P_CanResurrect(AActor *tmthing, AActor *thing) +{ + if (tmthing == nullptr) + return false; + + static unsigned VIndex = ~0u; + if (VIndex == ~0u) + { + VIndex = GetVirtualIndex(RUNTIME_CLASS(AActor), "CanResurrect"); + assert(VIndex != ~0u); + } + + VMValue params[3] = { tmthing, thing, false }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + + auto clss = tmthing->GetClass(); + VMFunction *func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; + if (func != nullptr) + { + VMCall(func, params, 3, &ret, 1); + if (!retval) return false; + } + + // Pointless to be running it again if it's just self. + if (thing == nullptr || thing == tmthing) + return true; + + std::swap(params[0].a, params[1].a); + params[2].i = true; + + // re-get for the other actor. + clss = thing->GetClass(); + func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; + if (func != nullptr) + { + VMCall(func, params, 3, &ret, 1); + if (!retval) return false; + } + return true; +} //========================================================================== // // P_CheckForResurrection (formerly part of A_VileChase) -// Check for ressurecting a body +// Check for resurrecting a body // //========================================================================== @@ -2834,7 +2886,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) corpsehit->flags = oldflags; corpsehit->radius = oldradius; corpsehit->Height = oldheight; - if (!check) continue; + if (!check || !P_CanResurrect(self, corpsehit)) continue; // got one! temp = self->target; diff --git a/src/p_local.h b/src/p_local.h index 9231058fd9..e9c2d0f2e7 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -162,6 +162,7 @@ void P_Thing_SetVelocity(AActor *actor, const DVector3 &vec, bool add, bool setb void P_RemoveThing(AActor * actor); bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck = false); bool P_Thing_CanRaise(AActor *thing); +bool P_CanResurrect(AActor *ththing, AActor *thing); PClassActor *P_GetSpawnableType(int spawnnum); void InitSpawnablesFromMapinfo(); int P_Thing_CheckInputNum(player_t *p, int inputnum); diff --git a/src/p_things.cpp b/src/p_things.cpp index 9fac1cd674..44ef08b949 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -460,6 +460,8 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser, int nocheck) return false; } + if (!P_CanResurrect(thing, raiser)) + return false; S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE); diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 3d4e74fc89..3ce5cf447e 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -445,6 +445,13 @@ class Actor : Thinker native return true; } + // Called by revival/resurrection to check if one can resurrect the other. + // "other" can be null when not passive. + virtual bool CanResurrect(Actor other, bool passive) + { + return true; + } + // Called when an actor is to be reflected by a disc of repulsion. // Returns true to continue normal blast processing. virtual bool SpecialBlastHandling (Actor source, double strength)