diff --git a/src/playsim/actor.h b/src/playsim/actor.h index c9465dbbf7..067324988e 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -442,7 +442,9 @@ enum ActorFlag9 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. MF9_SHADOWAIMVERT = 0x00000008, // [inkoalawetrust] Monster aim is also offset vertically when aiming at shadow actors. - MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states + MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states + MF9_BLOCKSIGHT = 0X00000020, // [inkoalawetrust] This actors' hitbox blocks P_CheckSight(). + MF9_DOBLOCKSIGHT = 0x00000040 // [inkoalawetrust] When calling P_CheckSight(), this actor checks for MF9_BLOCKSIGHT actors. }; // --- mobj.renderflags --- diff --git a/src/playsim/p_local.h b/src/playsim/p_local.h index ea40d386a8..e37b20f525 100644 --- a/src/playsim/p_local.h +++ b/src/playsim/p_local.h @@ -249,17 +249,17 @@ extern TArray spechit; extern TArray portalhit; -int P_TestMobjLocation (AActor *mobj); -int P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL); -bool P_CheckPosition(AActor *thing, const DVector2 &pos, bool actorsonly = false); -void P_DoMissileDamage(AActor* inflictor, AActor* target); -bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, bool actorsonly = false); -AActor *P_CheckOnmobj (AActor *thing); +int P_TestMobjLocation (AActor *mobj); +int P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL); +bool P_CheckPosition(AActor *thing, const DVector2 &pos, bool actorsonly = false); +void P_DoMissileDamage(AActor* inflictor, AActor* target); +bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, bool actorsonly = false); +AActor* P_CheckOnmobj (AActor *thing); void P_FakeZMovement (AActor *mo); bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); bool P_TryMove(AActor* thing, const DVector2 &pos, int dropoff, const secplane_t * onfloor = NULL, bool missilecheck = false); -bool P_CheckMove(AActor *thing, const DVector2 &pos, FCheckPosition& tm, int flags); +bool P_CheckMove(AActor *thing, const DVector2 &pos, FCheckPosition& tm, int flags); bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags = 0); void P_ApplyTorque(AActor *mo); @@ -270,7 +270,8 @@ void P_SlideMove (AActor* mo, const DVector2 &pos, int numsteps); bool P_BounceWall (AActor *mo); bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); bool P_ReflectOffActor(AActor* mo, AActor* blocking); -int P_CheckSight (AActor *t1, AActor *t2, int flags=0); +int P_CheckSight (AActor *t1, AActor *t2, int flags=0); +AActor* P_CheckForSightBlock(AActor* t1, AActor* t2); enum ESightFlags { diff --git a/src/playsim/p_sight.cpp b/src/playsim/p_sight.cpp index 2cf957c8ce..6cf842b9ca 100644 --- a/src/playsim/p_sight.cpp +++ b/src/playsim/p_sight.cpp @@ -36,6 +36,7 @@ #include "g_levellocals.h" #include "actorinlines.h" +#include "shadowinlines.h" static FRandom pr_botchecksight ("BotCheckSight"); static FRandom pr_checksight ("CheckSight"); @@ -838,6 +839,38 @@ sightcounts[2]++; ===================== */ +ETraceStatus CheckForSightBlockers(FTraceResults& res, void* userdata) +{ + SightCheckData* output = (SightCheckData*)userdata; + if (res.HitType == TRACE_HitActor && res.Actor && (res.Actor->flags9 & MF9_BLOCKSIGHT)) + { + output->HitSightBlocker = res.Actor; + return TRACE_Stop; + } + + if (res.HitType != TRACE_HitActor) + { + return TRACE_Stop; + } + + return TRACE_Continue; +} + +// [inkoalawetrust] Check if an MF9_BLOCKSIGHT actor is standing between t1 and t2. +AActor* P_CheckForSightBlock(AActor* t1, AActor* t2) +{ + FTraceResults result; + SightCheckData SightCheck; + SightCheck.HitSightBlocker = nullptr; + DVector3 dir = t1->Vec3To(t2); + double dist = dir.Length(); + DVector3 origin = t1->PosPlusZ(t1->Height * 0.75); //Standard sight checks are done at this height too. + + Trace(origin, t1->Sector, dir, dist, ActorFlags::FromInt(0xFFFFFFFF), ML_BLOCKEVERYTHING, t1, result, 0, CheckForSightBlockers, &SightCheck); + + return SightCheck.HitSightBlocker; +} + int P_CheckSight (AActor *t1, AActor *t2, int flags) { SightCycles.Clock(); @@ -904,6 +937,18 @@ sightcounts[0]++; } } + // [inkoalawetrust] All trivial checks passed, now check for MF9_BLOCKSIGHT + if (t1->flags9 & MF9_DOBLOCKSIGHT) + { + AActor* blocker = P_CheckForSightBlock(t1, t2); + + if (blocker != nullptr) + { + res = false; + goto done; + } + } + // An unobstructed LOS is possible. // Now look from eyes of t1 to any part of t2. diff --git a/src/playsim/shadowinlines.h b/src/playsim/shadowinlines.h index 60caa95069..94777a3f76 100644 --- a/src/playsim/shadowinlines.h +++ b/src/playsim/shadowinlines.h @@ -25,9 +25,11 @@ inline FRandom pr_shadowaimz("VerticalShadowAim"); // //========================================================================== +// Generic actor sight check data. struct SightCheckData { AActor* HitShadow; + AActor* HitSightBlocker; }; inline ETraceStatus CheckForShadowBlockers(FTraceResults& res, void* userdata) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 997ab78b1a..b1914ea144 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -353,6 +353,8 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9), DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9), DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9), + DEFINE_FLAG(MF9, BLOCKSIGHT, AActor, flags9), + DEFINE_FLAG(MF9, DOBLOCKSIGHT, AActor, flags9), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index c102120983..68897b9cd7 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -1453,6 +1453,13 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckSight, P_CheckSight) ACTION_RETURN_BOOL(P_CheckSight(self, target, flags)); } +DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckForSightBlocker, P_CheckForSightBlock) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); + ACTION_RETURN_OBJECT(P_CheckForSightBlock(self, target)); +} + static void GiveSecret(AActor *self, bool printmessage, bool playsound) { P_GiveSecret(self->Level, self, printmessage, playsound, -1); diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 0dc28c396e..1b1b541f4b 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -776,6 +776,7 @@ class Actor : Thinker native native Actor, int LineAttack(double angle, double distance, double pitch, int damage, Name damageType, class pufftype, int flags = 0, out FTranslatedLineTarget victim = null, double offsetz = 0., double offsetforward = 0., double offsetside = 0.); native bool LineTrace(double angle, double distance, double pitch, int flags = 0, double offsetz = 0., double offsetforward = 0., double offsetside = 0., out FLineTraceData data = null); native bool CheckSight(Actor target, int flags = 0); + native Actor CheckForSightBlocker (Actor target); native bool IsVisible(Actor other, bool allaround, LookExParams params = null); native bool, Actor, double PerformShadowChecks (Actor other, Vector3 pos); native bool HitFriend();