From c729b831afb4cee81f5de78aa477f671dda82d98 Mon Sep 17 00:00:00 2001 From: inkoalawetrust <56005600+inkoalawetrust@users.noreply.github.com> Date: Mon, 16 Jan 2023 22:49:47 +0200 Subject: [PATCH] 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. --- src/playsim/actor.h | 2 + src/playsim/p_actionfunctions.cpp | 2 +- src/playsim/p_mobj.cpp | 4 +- src/playsim/shadowinlines.h | 80 ++++++++++++++++++++++++++----- src/scripting/thingdef_data.cpp | 5 +- 5 files changed, 77 insertions(+), 16 deletions(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 199c93a98e..f73141fbc8 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -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 --- diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 5f4a444516..1f42650142 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -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)) diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 95b04ce3b6..870cee5c82 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -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); diff --git a/src/playsim/shadowinlines.h b/src/playsim/shadowinlines.h index 0a7144de4a..096fd65447 100644 --- a/src/playsim/shadowinlines.h +++ b/src/playsim/shadowinlines.h @@ -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()))); } \ No newline at end of file diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index aca5cfbc1f..cb4e58063e 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -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),