This commit is contained in:
Rachael Alexanderson 2016-12-26 17:26:55 -05:00
commit 6b2ddb0f3a
4 changed files with 84 additions and 41 deletions

View file

@ -1288,7 +1288,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode)
// Comparing the results of a test wad with Eternity, it seems A_NailBomb does not aim // 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), //P_AimLineAttack (self, ang, MISSILERANGE),
naildamage, NAME_Hitscan, pufftype); naildamage, NAME_Hitscan, pufftype, (self->flags & MF_MISSILE) ? LAF_TARGETISSOURCE : 0);
} }
} }

View file

@ -323,6 +323,7 @@ enum // P_LineAttack flags
LAF_NORANDOMPUFFZ = 2, LAF_NORANDOMPUFFZ = 2,
LAF_NOIMPACTDECAL = 4, LAF_NOIMPACTDECAL = 4,
LAF_NOINTERACT = 8, 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); 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);

View file

@ -82,6 +82,56 @@ static FRandom pr_crunch("DoCrunch");
TArray<spechit_t> spechit; TArray<spechit_t> spechit;
TArray<spechit_t> portalhit; TArray<spechit_t> 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 // 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 // monsters don't stomp things except on boss level
// [RH] Some Heretic/Hexen monsters can telestomp // [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. // ... 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) bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm)
{ {
AActor *thing = cres.thing; 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))) && 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))) ((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 (!P_CanCollideWith(tm.thing, thing)) return true;
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;
}
} }
@ -1959,6 +1977,12 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj)
{ // something higher is in the way { // something higher is in the way
continue; continue;
} }
else if (!P_CanCollideWith(actor, thing))
{ // If they cannot collide, they cannot block each other.
continue;
}
onmobj = thing; onmobj = thing;
if (quick) break; if (quick) break;
} }
@ -4476,7 +4500,9 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
puff = P_SpawnPuff(t1, pufftype, bleedpos, 0., 0., 2, puffFlags | PF_HITTHING | PF_TEMPORARY); puff = P_SpawnPuff(t1, pufftype, bleedpos, 0., 0., 2, puffFlags | PF_HITTHING | PF_TEMPORARY);
killPuff = true; 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) if (actualdamage != NULL)
{ {
*actualdamage = newdam; *actualdamage = newdam;
@ -5943,6 +5969,9 @@ int P_PushUp(AActor *thing, FChangePosition *cpos)
continue; continue;
if ((thing->flags & MF_MISSILE) && (intersect->flags2 & MF2_REFLECTIVE) && (intersect->flags7 & MF7_THRUREFLECT)) if ((thing->flags & MF_MISSILE) && (intersect->flags2 & MF2_REFLECTIVE) && (intersect->flags7 & MF7_THRUREFLECT))
continue; continue;
if (!P_CanCollideWith(thing, intersect))
continue;
if (!(intersect->flags2 & MF2_PASSMOBJ) || if (!(intersect->flags2 & MF2_PASSMOBJ) ||
(!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) ||
(intersect->flags4 & MF4_ACTLIKEBRIDGE) (intersect->flags4 & MF4_ACTLIKEBRIDGE)
@ -5989,6 +6018,18 @@ int P_PushDown(AActor *thing, FChangePosition *cpos)
for (; firstintersect < lastintersect; firstintersect++) for (; firstintersect < lastintersect; firstintersect++)
{ {
AActor *intersect = intersectors[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) || if (!(intersect->flags2 & MF2_PASSMOBJ) ||
(!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) ||
(intersect->flags4 & MF4_ACTLIKEBRIDGE) (intersect->flags4 & MF4_ACTLIKEBRIDGE)

View file

@ -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 // the referenced sound so some additional checks are required
int near_limit = sfx->NearLimit; int near_limit = sfx->NearLimit;
float limit_range = sfx->LimitRange; float limit_range = sfx->LimitRange;
auto pitchmask = sfx->PitchMask;
rolloff = &sfx->Rolloff; rolloff = &sfx->Rolloff;
// Resolve player sounds, random sounds, and aliases // 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. // 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 else
{ {