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:
inkoalawetrust 2023-01-16 22:49:47 +02:00 committed by Rachael Alexanderson
parent 162dbf0554
commit c729b831af
5 changed files with 77 additions and 16 deletions

View file

@ -439,6 +439,8 @@ enum ActorFlag8
enum ActorFlag9
{
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 ---

View file

@ -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);
}
A_CustomRailgun_ShadowHandling(self);
A_CustomRailgun_ShadowHandling(self, spawnofs_xy, spawnofs_z, spread_xy, flags);
}
if (!(flags & CRF_EXPLICITANGLE))

View file

@ -6706,7 +6706,7 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct
}
th->Vel = velocity.Resized(speed);
P_SpawnMissileXYZ_ShadowHandling(source,dest,th);
P_SpawnMissileXYZ_ShadowHandling(source,dest,th,pos);
th->AngleFromVel();
@ -6828,7 +6828,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActo
an = source->Angles.Yaw;
an += P_SpawnMissileZAimed_ShadowHandling(source,dest);
an += P_SpawnMissileZAimed_ShadowHandling(source,dest,source->PosAtZ(z));
dist = source->Distance2D (dest);
speed = GetDefaultSpeed (type);

View file

@ -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
// [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));
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.
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.));
}
@ -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)
{
// 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.));
}
@ -76,16 +122,28 @@ inline void A_Face_ShadowHandling(AActor* self, AActor* other, DAngle max_turn,
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);
}
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.));
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.
inline bool A_WolfAttack_ShadowHandling(AActor* self)
{
return (CheckShadowFlags(self, self->target));
return (PerformShadowChecks(self, self->target, self->PosAtZ(self->Center())));
}

View file

@ -348,6 +348,8 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(MF8, ONLYSLAMSOLID, AActor, flags8),
DEFINE_FLAG(MF9, SHADOWAIM, AActor, flags9),
DEFINE_FLAG(MF9, DOSHADOWBLOCK, AActor, flags9),
DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
@ -357,8 +359,7 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(RF, FORCEYBILLBOARD, AActor, renderflags),
DEFINE_FLAG(RF, FORCEXYBILLBOARD, AActor, renderflags),
DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard
// [fgsfds] Flat sprites
DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags), // [fgsfds] Flat sprites
DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags),
DEFINE_FLAG(RF, ROLLCENTER, AActor, renderflags),