From fc6191deb9235650d874a599ea73ca2c58c859f8 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Sat, 16 Dec 2023 01:23:32 -0500 Subject: [PATCH] Added CollidedWith Guarantees a collision happened unlike CanCollideWith. Called in TryMove so it only calls when an actual movement was attempted and not just a potential positional check. --- src/playsim/p_map.cpp | 29 ++++++++++++++++++++++++++- wadsrc/static/zscript/actors/actor.zs | 4 ++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index 636304db8..84d3c40e1 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -2257,6 +2257,25 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, DVector2 * } } +static void P_CollidedWith(AActor* const collider, AActor* const collidee) +{ + { + IFVIRTUALPTR(collider, AActor, CollidedWith) + { + VMValue params[] = { collider, collidee, false }; + VMCall(func, params, 3, nullptr, 0); + } + } + + { + IFVIRTUALPTR(collidee, AActor, CollidedWith) + { + VMValue params[] = { collidee, collider, true }; + VMCall(func, params, 3, nullptr, 0); + } + } +} + //========================================================================== // // P_TryMove @@ -2289,6 +2308,11 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, if (!P_CheckPosition(thing, pos, tm)) { AActor *BlockingMobj = thing->BlockingMobj; + // This gets called regardless of whether or not the following checks allow the thing to pass. This is because a player + // could step on top of an enemy but we still want it to register as a collision. + if (BlockingMobj != nullptr && (thing->player == nullptr || !(thing->player->cheats & CF_PREDICTING))) + P_CollidedWith(thing, BlockingMobj); + // Solid wall or thing if (!BlockingMobj || BlockingMobj->player || !thing->player) { @@ -2567,6 +2591,9 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, thing->SetXYZ(thingpos.X, thingpos.Y, pos.Z); if (!P_CheckPosition(thing, pos.XY(), true)) // check if some actor blocks us on the other side. (No line checks, because of the mess that'd create.) { + if (thing->BlockingMobj != nullptr && (thing->player == nullptr || !(thing->player->cheats && CF_PREDICTING))) + P_CollidedWith(thing, thing->BlockingMobj); + thing->SetXYZ(oldthingpos); thing->flags6 &= ~MF6_INTRYMOVE; return false; @@ -2744,6 +2771,7 @@ bool P_TryMove(AActor *thing, const DVector2 &pos, pushline: thing->flags6 &= ~MF6_INTRYMOVE; + thing->SetZ(oldz); // [RH] Don't activate anything if just predicting if (thing->player && (thing->player->cheats & CF_PREDICTING)) @@ -2751,7 +2779,6 @@ pushline: return false; } - thing->SetZ(oldz); if (!(thing->flags&(MF_TELEPORT | MF_NOCLIP))) { int numSpecHitTemp; diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index c9874596f..8b63881f5 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -510,6 +510,10 @@ class Actor : Thinker native return true; } + // Called in TryMove if the mover ran into another Actor. This isn't called on players + // if they're currently predicting. Guarantees collisions unlike CanCollideWith. + virtual void CollidedWith(Actor other, bool passive) {} + // Called by PIT_CheckThing to check if two actors actually can collide. virtual bool CanCollideWith(Actor other, bool passive) {