mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 20:21:26 +00:00
Added MF9_SHADOWBLOCK.
Actors in the line of fire with this flag trigger the MF_SHADOW aiming penalty. The shooter needs to have MF9_DOSHADOWBLOCK to check for actors with this flag.
This commit is contained in:
parent
162dbf0554
commit
c729b831af
5 changed files with 77 additions and 16 deletions
|
@ -439,6 +439,8 @@ enum ActorFlag8
|
||||||
enum ActorFlag9
|
enum ActorFlag9
|
||||||
{
|
{
|
||||||
MF9_SHADOWAIM = 0x00000001, // [inkoalawetrust] Monster still gets aim penalty from aiming at shadow actors even with MF6_SEEINVISIBLE on.
|
MF9_SHADOWAIM = 0x00000001, // [inkoalawetrust] Monster still gets aim penalty from aiming at shadow actors even with MF6_SEEINVISIBLE on.
|
||||||
|
MF9_DOSHADOWBLOCK = 0x00000002, // [inkoalawetrust] Should the monster look for SHADOWBLOCK actors ?
|
||||||
|
MF9_SHADOWBLOCK = 0x00000004, // [inkoalawetrust] Actors in the line of fire with this flag trigger the MF_SHADOW aiming penalty.
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- mobj.renderflags ---
|
// --- mobj.renderflags ---
|
||||||
|
|
|
@ -1227,7 +1227,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomRailgun)
|
||||||
self->Angles.Yaw = self->AngleTo(self->target,- self->target->Vel.X * veleffect, -self->target->Vel.Y * veleffect);
|
self->Angles.Yaw = self->AngleTo(self->target,- self->target->Vel.X * veleffect, -self->target->Vel.Y * veleffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
A_CustomRailgun_ShadowHandling(self);
|
A_CustomRailgun_ShadowHandling(self, spawnofs_xy, spawnofs_z, spread_xy, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(flags & CRF_EXPLICITANGLE))
|
if (!(flags & CRF_EXPLICITANGLE))
|
||||||
|
|
|
@ -6706,7 +6706,7 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct
|
||||||
}
|
}
|
||||||
th->Vel = velocity.Resized(speed);
|
th->Vel = velocity.Resized(speed);
|
||||||
|
|
||||||
P_SpawnMissileXYZ_ShadowHandling(source,dest,th);
|
P_SpawnMissileXYZ_ShadowHandling(source,dest,th,pos);
|
||||||
|
|
||||||
th->AngleFromVel();
|
th->AngleFromVel();
|
||||||
|
|
||||||
|
@ -6828,7 +6828,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActo
|
||||||
|
|
||||||
an = source->Angles.Yaw;
|
an = source->Angles.Yaw;
|
||||||
|
|
||||||
an += P_SpawnMissileZAimed_ShadowHandling(source,dest);
|
an += P_SpawnMissileZAimed_ShadowHandling(source,dest,source->PosAtZ(z));
|
||||||
|
|
||||||
dist = source->Distance2D (dest);
|
dist = source->Distance2D (dest);
|
||||||
speed = GetDefaultSpeed (type);
|
speed = GetDefaultSpeed (type);
|
||||||
|
|
|
@ -24,9 +24,55 @@ extern FRandom pr_crailgun;
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
inline bool CheckShadowFlags(AActor* self, AActor* other)
|
struct ShadowCheckData
|
||||||
{
|
{
|
||||||
return (other->flags & MF_SHADOW && (!(self->flags6 & MF6_SEEINVISIBLE) || self->flags9 & MF9_SHADOWAIM));
|
bool HitShadow;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ETraceStatus CheckForShadowBlockers(FTraceResults& res, void* userdata)
|
||||||
|
{
|
||||||
|
ShadowCheckData* output = (ShadowCheckData*)userdata;
|
||||||
|
if (res.HitType == TRACE_HitActor && res.Actor && (res.Actor->flags9 & MF9_SHADOWBLOCK))
|
||||||
|
{
|
||||||
|
output->HitShadow = true;
|
||||||
|
return TRACE_Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.HitType != TRACE_HitActor)
|
||||||
|
{
|
||||||
|
return TRACE_Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRACE_Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [inkoalawetrust] Check if an MF9_SHADOWBLOCK actor is standing between t1 and t2.
|
||||||
|
inline bool P_CheckForShadowBlock(AActor* t1, AActor* t2, DVector3 pos)
|
||||||
|
{
|
||||||
|
FTraceResults result;
|
||||||
|
ShadowCheckData ShadowCheck;
|
||||||
|
ShadowCheck.HitShadow = false;
|
||||||
|
DVector3 dir = t1->Vec3To(t2);
|
||||||
|
double dist = dir.Length();
|
||||||
|
|
||||||
|
Trace(pos, t1->Sector, dir, dist, ActorFlags::FromInt(0xFFFFFFFF), ML_BLOCKEVERYTHING, t1, result, 0, CheckForShadowBlockers, &ShadowCheck);
|
||||||
|
|
||||||
|
return ShadowCheck.HitShadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool AffectedByShadows(AActor* self, AActor* other)
|
||||||
|
{
|
||||||
|
return (!(self->flags6 & MF6_SEEINVISIBLE) || self->flags9 & MF9_SHADOWAIM);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool CheckForShadows(AActor* self, AActor* other, DVector3 pos)
|
||||||
|
{
|
||||||
|
return (other->flags & MF_SHADOW || self->flags9 & MF9_DOSHADOWBLOCK && P_CheckForShadowBlock(self, other, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool PerformShadowChecks(AActor* self, AActor* other, DVector3 pos)
|
||||||
|
{
|
||||||
|
return (AffectedByShadows(self, other) && CheckForShadows(self, other, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -35,11 +81,11 @@ inline bool CheckShadowFlags(AActor* self, AActor* other)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
inline void P_SpawnMissileXYZ_ShadowHandling(AActor* source, AActor* target, AActor* missile)
|
inline void P_SpawnMissileXYZ_ShadowHandling(AActor* source, AActor* target, AActor* missile, DVector3 pos)
|
||||||
{
|
{
|
||||||
// invisible target: rotate velocity vector in 2D
|
// invisible target: rotate velocity vector in 2D
|
||||||
// [RC] Now monsters can aim at invisible player as if they were fully visible.
|
// [RC] Now monsters can aim at invisible player as if they were fully visible.
|
||||||
if (CheckShadowFlags(source,target))
|
if (PerformShadowChecks(source,target,pos))
|
||||||
{
|
{
|
||||||
DAngle an = DAngle::fromDeg(pr_spawnmissile.Random2() * (22.5 / 256));
|
DAngle an = DAngle::fromDeg(pr_spawnmissile.Random2() * (22.5 / 256));
|
||||||
double c = an.Cos();
|
double c = an.Cos();
|
||||||
|
@ -55,9 +101,9 @@ inline void P_SpawnMissileXYZ_ShadowHandling(AActor* source, AActor* target, AAc
|
||||||
}
|
}
|
||||||
|
|
||||||
//P_SpawnMissileZAimed uses a local variable for the angle it passes on.
|
//P_SpawnMissileZAimed uses a local variable for the angle it passes on.
|
||||||
inline DAngle P_SpawnMissileZAimed_ShadowHandling(AActor* source, AActor* target)
|
inline DAngle P_SpawnMissileZAimed_ShadowHandling(AActor* source, AActor* target, DVector3 pos)
|
||||||
{
|
{
|
||||||
if (CheckShadowFlags(source,target))
|
if (PerformShadowChecks(source,target,pos))
|
||||||
{
|
{
|
||||||
return DAngle::fromDeg(pr_spawnmissile.Random2() * (16. / 360.));
|
return DAngle::fromDeg(pr_spawnmissile.Random2() * (16. / 360.));
|
||||||
}
|
}
|
||||||
|
@ -67,7 +113,7 @@ inline DAngle P_SpawnMissileZAimed_ShadowHandling(AActor* source, AActor* target
|
||||||
inline void A_Face_ShadowHandling(AActor* self, AActor* other, DAngle max_turn, DAngle other_angle)
|
inline void A_Face_ShadowHandling(AActor* self, AActor* other, DAngle max_turn, DAngle other_angle)
|
||||||
{
|
{
|
||||||
// This will never work well if the turn angle is limited.
|
// This will never work well if the turn angle is limited.
|
||||||
if (max_turn == nullAngle && (self->Angles.Yaw == other_angle) && CheckShadowFlags(self, other))
|
if (max_turn == nullAngle && (self->Angles.Yaw == other_angle) && PerformShadowChecks(self, other,self->PosAtZ(self->Center())))
|
||||||
{
|
{
|
||||||
self->Angles.Yaw += DAngle::fromDeg(pr_facetarget.Random2() * (45 / 256.));
|
self->Angles.Yaw += DAngle::fromDeg(pr_facetarget.Random2() * (45 / 256.));
|
||||||
}
|
}
|
||||||
|
@ -76,16 +122,28 @@ inline void A_Face_ShadowHandling(AActor* self, AActor* other, DAngle max_turn,
|
||||||
|
|
||||||
inline void A_MonsterRail_ShadowHandling(AActor* self)
|
inline void A_MonsterRail_ShadowHandling(AActor* self)
|
||||||
{
|
{
|
||||||
if (CheckShadowFlags(self, self->target))
|
double shootZ = self->Center() - self->FloatSpeed - self->Floorclip; // The formula P_RailAttack uses, minus offset_z since A_MonsterRail doesn't use it.
|
||||||
|
|
||||||
|
if (PerformShadowChecks(self, self->target,self->PosAtZ(shootZ)))
|
||||||
{
|
{
|
||||||
self->Angles.Yaw += DAngle::fromDeg(pr_railface.Random2() * 45. / 256);
|
self->Angles.Yaw += DAngle::fromDeg(pr_railface.Random2() * 45. / 256);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void A_CustomRailgun_ShadowHandling(AActor* self)
|
//Also passes parameters to determine a firing position for the SHADOWBLOCK check.
|
||||||
|
inline void A_CustomRailgun_ShadowHandling(AActor* self, double spawnofs_xy, double spawnofs_z, DAngle spread_xy, int flags)
|
||||||
{
|
{
|
||||||
if (CheckShadowFlags(self, self->target))
|
// [inkoalawetrust] The exact formula P_RailAttack uses to determine where the railgun trace should spawn from.
|
||||||
|
DVector2 shootXY = (self->Vec2Angle(spawnofs_xy, (self->Angles.Yaw + spread_xy) - DAngle::fromDeg(90.)));
|
||||||
|
double shootZ = self->Center() - self->FloatSpeed + spawnofs_z - self->Floorclip;
|
||||||
|
if (flags & 16) shootZ += self->AttackOffset(); //16 is RGF_CENTERZ
|
||||||
|
DVector3 checkPos;
|
||||||
|
checkPos.X = shootXY.X;
|
||||||
|
checkPos.Y = shootXY.Y;
|
||||||
|
checkPos.Z = shootZ;
|
||||||
|
|
||||||
|
if (PerformShadowChecks(self, self->target, checkPos))
|
||||||
{
|
{
|
||||||
DAngle rnd = DAngle::fromDeg(pr_crailgun.Random2() * (45. / 256.));
|
DAngle rnd = DAngle::fromDeg(pr_crailgun.Random2() * (45. / 256.));
|
||||||
self->Angles.Yaw += rnd;
|
self->Angles.Yaw += rnd;
|
||||||
|
@ -96,5 +154,5 @@ inline void A_CustomRailgun_ShadowHandling(AActor* self)
|
||||||
//A_WolfAttack directly harms the target instead of firing a hitscan or projectile. So it handles shadows by lowering the chance of harming the target.
|
//A_WolfAttack directly harms the target instead of firing a hitscan or projectile. So it handles shadows by lowering the chance of harming the target.
|
||||||
inline bool A_WolfAttack_ShadowHandling(AActor* self)
|
inline bool A_WolfAttack_ShadowHandling(AActor* self)
|
||||||
{
|
{
|
||||||
return (CheckShadowFlags(self, self->target));
|
return (PerformShadowChecks(self, self->target, self->PosAtZ(self->Center())));
|
||||||
}
|
}
|
|
@ -348,6 +348,8 @@ static FFlagDef ActorFlagDefs[]=
|
||||||
DEFINE_FLAG(MF8, ONLYSLAMSOLID, AActor, flags8),
|
DEFINE_FLAG(MF8, ONLYSLAMSOLID, AActor, flags8),
|
||||||
|
|
||||||
DEFINE_FLAG(MF9, SHADOWAIM, AActor, flags9),
|
DEFINE_FLAG(MF9, SHADOWAIM, AActor, flags9),
|
||||||
|
DEFINE_FLAG(MF9, DOSHADOWBLOCK, AActor, flags9),
|
||||||
|
DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9),
|
||||||
|
|
||||||
// Effect flags
|
// Effect flags
|
||||||
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
||||||
|
@ -357,8 +359,7 @@ static FFlagDef ActorFlagDefs[]=
|
||||||
DEFINE_FLAG(RF, FORCEYBILLBOARD, AActor, renderflags),
|
DEFINE_FLAG(RF, FORCEYBILLBOARD, AActor, renderflags),
|
||||||
DEFINE_FLAG(RF, FORCEXYBILLBOARD, AActor, renderflags),
|
DEFINE_FLAG(RF, FORCEXYBILLBOARD, AActor, renderflags),
|
||||||
DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard
|
DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard
|
||||||
// [fgsfds] Flat sprites
|
DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags), // [fgsfds] Flat sprites
|
||||||
DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
|
|
||||||
DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
|
DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
|
||||||
DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags),
|
DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags),
|
||||||
DEFINE_FLAG(RF, ROLLCENTER, AActor, renderflags),
|
DEFINE_FLAG(RF, ROLLCENTER, AActor, renderflags),
|
||||||
|
|
Loading…
Reference in a new issue