From 53270554951a3b97d65b96b12ce444833c6dd614 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 26 Dec 2016 20:37:04 +0100 Subject: [PATCH 1/3] - fixed: Source for nailbomb damage in A_Explode should be the caller's target, if defined and the caller is a missile. --- src/p_actionfunctions.cpp | 4 ++-- src/p_local.h | 1 + src/p_map.cpp | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 4136ec331..5bf5bf450 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1286,9 +1286,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode) { ang = i*360./nails; // Comparing the results of a test wad with Eternity, it seems A_NailBomb does not aim - P_LineAttack (self, ang, MISSILERANGE, 0., + P_LineAttack(self, ang, MISSILERANGE, 0., //P_AimLineAttack (self, ang, MISSILERANGE), - naildamage, NAME_Hitscan, pufftype); + naildamage, NAME_Hitscan, pufftype, (self->flags & MF_MISSILE) ? LAF_TARGETISSOURCE : 0); } } diff --git a/src/p_local.h b/src/p_local.h index 93bbbbf11..41f980d44 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -323,6 +323,7 @@ enum // P_LineAttack flags LAF_NORANDOMPUFFZ = 2, LAF_NOIMPACTDECAL = 4, LAF_NOINTERACT = 8, + LAF_TARGETISSOURCE = 16, }; AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL); diff --git a/src/p_map.cpp b/src/p_map.cpp index 85c3e3da8..560b39de6 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4476,7 +4476,9 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, puff = P_SpawnPuff(t1, pufftype, bleedpos, 0., 0., 2, puffFlags | PF_HITTHING | PF_TEMPORARY); killPuff = true; } - newdam = P_DamageMobj(trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags|DMG_USEANGLE, trace.SrcAngleFromTarget); + auto src = t1; + if ((flags & LAF_TARGETISSOURCE) && t1 && t1->target) src = t1->target; + newdam = P_DamageMobj(trace.Actor, puff ? puff : t1, src, damage, damageType, dmgflags|DMG_USEANGLE, trace.SrcAngleFromTarget); if (actualdamage != NULL) { *actualdamage = newdam; From 58316c821d42bd0315230447e611d73e42e8ac6e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 26 Dec 2016 21:07:21 +0100 Subject: [PATCH 2/3] - fixed: The pitch shifting info for sounds needs to be taken from the sfxinfo currently being played, not the one it links to. --- src/s_sound.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index fd15b9491..be1b572f1 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -917,6 +917,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO // the referenced sound so some additional checks are required int near_limit = sfx->NearLimit; float limit_range = sfx->LimitRange; + auto pitchmask = sfx->PitchMask; rolloff = &sfx->Rolloff; // Resolve player sounds, random sounds, and aliases @@ -1081,9 +1082,9 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO } // Vary the sfx pitches. - if (sfx->PitchMask != 0) + if (pitchmask != 0) { - pitch = NORM_PITCH - (M_Random() & sfx->PitchMask) + (M_Random() & sfx->PitchMask); + pitch = NORM_PITCH - (M_Random() & pitchmask) + (M_Random() & pitchmask); } else { From e9574276a559ff7bf0d0043e3531c3c819ae4c30 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 26 Dec 2016 22:33:07 +0100 Subject: [PATCH 3/3] - added CanCollideWith calls to a few more places where they are needed. --- src/p_map.cpp | 111 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 36 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 560b39de6..913840e59 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -82,6 +82,56 @@ static FRandom pr_crunch("DoCrunch"); TArray spechit; TArray portalhit; + +//========================================================================== +// +// CanCollideWith +// +// Checks if an actor can collide with another one, calling virtual script functions to check. +// +//========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, CanCollideWith) +{ + // No need to check the parameters, as they are not even used. + ACTION_RETURN_BOOL(true); +} + +bool P_CanCollideWith(AActor *tmthing, AActor *thing) +{ + static unsigned VIndex = ~0u; + if (VIndex == ~0u) + { + VIndex = GetVirtualIndex(RUNTIME_CLASS(AActor), "CanCollideWith"); + 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) + { + GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); + if (!retval) return false; + } + 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) + { + GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); + if (!retval) return false; + } + return true; +} + //========================================================================== // // FindRefPoint @@ -402,6 +452,9 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi } } + if (!P_CanCollideWith(tmf.thing, th)) + continue; + // monsters don't stomp things except on boss level // [RH] Some Heretic/Hexen monsters can telestomp // ... and some items can never be telefragged while others will be telefragged by everything that teleports upon them. @@ -1147,12 +1200,6 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) // //========================================================================== -DEFINE_ACTION_FUNCTION(AActor, CanCollideWith) -{ - // No need to check the parameters, as they are not even used. - ACTION_RETURN_BOOL(true); -} - bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm) { AActor *thing = cres.thing; @@ -1257,36 +1304,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch if (((thing->flags & MF_SOLID) || (thing->flags6 & (MF6_TOUCHY | MF6_BUMPSPECIAL))) && ((tm.thing->flags & (MF_SOLID|MF_MISSILE)) || (tm.thing->flags2 & MF2_BLASTED) || (tm.thing->flags6 & MF6_BLOCKEDBYSOLIDACTORS) || (tm.thing->BounceFlags & BOUNCE_MBF))) { - static unsigned VIndex = ~0u; - if (VIndex == ~0u) - { - VIndex = GetVirtualIndex(RUNTIME_CLASS(AActor), "CanCollideWith"); - assert(VIndex != ~0u); - } - - VMValue params[3] = { tm.thing, thing, false }; - VMReturn ret; - int retval; - ret.IntAt(&retval); - - auto clss = tm.thing->GetClass(); - VMFunction *func = clss->Virtuals.Size() > VIndex ? clss->Virtuals[VIndex] : nullptr; - if (func != nullptr) - { - GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); - if (!retval) 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) - { - GlobalVMStack.Call(func, params, 3, &ret, 1, nullptr); - if (!retval) return true; - } + if (!P_CanCollideWith(tm.thing, thing)) return true; } @@ -1959,6 +1977,12 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj) { // something higher is in the way continue; } + else if (!P_CanCollideWith(actor, thing)) + { // If they cannot collide, they cannot block each other. + continue; + } + + onmobj = thing; if (quick) break; } @@ -5945,6 +5969,9 @@ int P_PushUp(AActor *thing, FChangePosition *cpos) continue; if ((thing->flags & MF_MISSILE) && (intersect->flags2 & MF2_REFLECTIVE) && (intersect->flags7 & MF7_THRUREFLECT)) continue; + if (!P_CanCollideWith(thing, intersect)) + continue; + if (!(intersect->flags2 & MF2_PASSMOBJ) || (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || (intersect->flags4 & MF4_ACTLIKEBRIDGE) @@ -5991,6 +6018,18 @@ int P_PushDown(AActor *thing, FChangePosition *cpos) for (; firstintersect < lastintersect; firstintersect++) { AActor *intersect = intersectors[firstintersect]; + + // [GZ] Skip this iteration for THRUSPECIES things + // Should there be MF2_THRUGHOST / MF3_GHOST checks there too for consistency? + // Or would that risk breaking established behavior? THRUGHOST, like MTHRUSPECIES, + // is normally for projectiles which would have exploded by now anyway... + if (thing->flags6 & MF6_THRUSPECIES && thing->GetSpecies() == intersect->GetSpecies()) + continue; + if ((thing->flags & MF_MISSILE) && (intersect->flags2 & MF2_REFLECTIVE) && (intersect->flags7 & MF7_THRUREFLECT)) + continue; + if (!P_CanCollideWith(thing, intersect)) + continue; + if (!(intersect->flags2 & MF2_PASSMOBJ) || (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || (intersect->flags4 & MF4_ACTLIKEBRIDGE)