From 69e8c9ec6edfb80b4a5fac9f5434227dd567ab32 Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Fri, 19 Jan 2018 00:29:49 +0100 Subject: [PATCH] A more "general purpose" line trace function. Far from a complete ZScript interface with Trace(), though. --- src/p_linetracedata.h | 25 +++++ src/p_local.h | 12 +++ src/p_map.cpp | 154 ++++++++++++++++++++++++++++ wadsrc/static/zscript/actor.txt | 27 +++++ wadsrc/static/zscript/constants.txt | 12 +++ 5 files changed, 230 insertions(+) create mode 100644 src/p_linetracedata.h diff --git a/src/p_linetracedata.h b/src/p_linetracedata.h new file mode 100644 index 000000000..f6191b5d1 --- /dev/null +++ b/src/p_linetracedata.h @@ -0,0 +1,25 @@ +#ifndef P_LTRACEDATA_H +#define P_LTRACEDATA_H + +//============================================================================ +// +// Structure for passing detailed results of LineTrace to ZScript +// +//============================================================================ +struct FLineTraceData +{ + AActor *HitActor; + line_t *HitLine; + sector_t *HitSector; + F3DFloor *Hit3DFloor; + FTextureID HitTexture; + DVector3 HitLocation; + double Distance; + int NumPortals; + int LineSide; + int LinePart; + int SectorPlane; + ETraceResult HitType; +}; + +#endif diff --git a/src/p_local.h b/src/p_local.h index 2f12b6a5b..d22d8a7ef 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -336,6 +336,18 @@ enum // P_LineAttack flags 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, double sz = 0.0, double offsetforward = 0.0, double offsetside = 0.0); AActor *P_LineAttack(AActor *t1, DAngle angle, double distance, DAngle pitch, int damage, FName damageType, FName pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL, double sz = 0.0, double offsetforward = 0.0, double offsetside = 0.0); +enum // P_LineTrace flags +{ + TRF_ABSPOSITION = 1, + TRF_ABSOFFSET = 2, + TRF_THRUSPECIES = 4, + TRF_THRUACTORS = 8, + TRF_THRUBLOCK = 16, + TRF_THRUHITSCAN = 32, + TRF_NOSKY = 64, + TRF_ALLACTORS = 128, +}; + void P_TraceBleed(int damage, const DVector3 &pos, AActor *target, DAngle angle, DAngle pitch); void P_TraceBleed(int damage, AActor *target, DAngle angle, DAngle pitch); diff --git a/src/p_map.cpp b/src/p_map.cpp index 304cfd8cf..8f04d24a5 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -79,6 +79,7 @@ #include "p_terrain.h" #include "p_trace.h" #include "p_checkposition.h" +#include "p_linetracedata.h" #include "r_utility.h" #include "p_blockmap.h" #include "p_3dmidtex.h" @@ -4814,6 +4815,159 @@ DEFINE_ACTION_FUNCTION(AActor, LineAttack) return numret; } +//========================================================================== +// +// P_LineTrace +// +//========================================================================== +struct LineTraceData +{ + AActor *Caller; + bool ThruSpecies; + bool ThruActors; + int NumPortals; +}; + +static ETraceStatus CheckLineTrace(FTraceResults &res, void *userdata) +{ + LineTraceData *TData = (LineTraceData *)userdata; + if ( res.HitType == TRACE_CrossingPortal ) + { + TData->NumPortals++; + return TRACE_Skip; + } + if ( res.HitType != TRACE_HitActor ) + { + return TRACE_Stop; + } + if ( (TData->ThruActors) || (TData->ThruSpecies && res.Actor->GetSpecies() == TData->Caller->GetSpecies()) ) + { + return TRACE_Skip; + } + return TRACE_Stop; +} + +bool P_LineTrace(AActor *t1, DAngle angle, double distance, + DAngle pitch, int flags, double sz, double offsetforward, + double offsetside, FLineTraceData *outdata) +{ + FTraceResults trace; + LineTraceData TData; + TData.Caller = t1; + TData.ThruSpecies = (flags & TRF_THRUSPECIES); + TData.ThruActors = (flags & TRF_THRUACTORS); + TData.NumPortals = 0; + DVector3 direction; + double pc = pitch.Cos(); + direction = { pc * angle.Cos(), pc * angle.Sin(), -pitch.Sin() }; + DVector3 startpos; + double startz = t1->Z() - t1->Floorclip; + startz += sz; + if ( flags & TRF_ABSPOSITION ) + { + startpos = DVector3(offsetforward, offsetside, sz); + } + else if ( flags & TRF_ABSOFFSET ) + { + startpos = t1->Vec2OffsetZ(offsetforward, offsetside, startz); + } + else if ( (offsetforward == 0.0) && (offsetside == 0.0) ) + { + startpos = t1->PosAtZ(startz); + } + else + { + const double s = angle.Sin(); + const double c = angle.Cos(); + startpos = t1->Vec2OffsetZ(offsetforward * c + offsetside * s, offsetforward * s - offsetside * c, startz); + } + + ActorFlags aflags = (flags & TRF_ALLACTORS) ? ActorFlags::FromInt(0xFFFFFFFF) : MF_SHOOTABLE; + int lflags = 0; + if ( !(lflags & TRF_THRUBLOCK) ) lflags |= ML_BLOCKEVERYTHING; + if ( !(lflags & TRF_THRUHITSCAN) ) lflags |= ML_BLOCKHITSCAN; + int tflags = TRACE_ReportPortals; + if ( flags & TRF_NOSKY ) tflags |= TRACE_NoSky; + + // Do trace + bool ret = Trace(startpos, t1->Sector, direction, distance, aflags, lflags, t1, trace, tflags, CheckLineTrace, &TData); + if ( outdata ) + { + memset(outdata,0,sizeof(*outdata)); + outdata->HitActor = trace.Actor; + outdata->HitLine = trace.Line; + outdata->HitSector = trace.Sector; + outdata->Hit3DFloor = trace.ffloor; + switch ( trace.HitType ) + { + case TRACE_HitFloor: + outdata->SectorPlane = 0; + outdata->HitTexture = trace.Sector->planes[0].Texture; + break; + case TRACE_HitCeiling: + outdata->SectorPlane = 1; + outdata->HitTexture = trace.Sector->planes[1].Texture; + break; + case TRACE_HitWall: + outdata->LineSide = trace.Side; + int txpart; + switch ( trace.Tier ) + { + case TIER_Middle: + outdata->LinePart = 1; + outdata->HitTexture = trace.Line->sidedef[trace.Side]->textures[1].texture; + break; + case TIER_Upper: + outdata->LinePart = 0; + outdata->HitTexture = trace.Line->sidedef[trace.Side]->textures[0].texture; + break; + case TIER_Lower: + outdata->LinePart = 2; + outdata->HitTexture = trace.Line->sidedef[trace.Side]->textures[2].texture; + break; + case TIER_FFloor: + txpart = (trace.ffloor->flags & FF_UPPERTEXTURE) ? 0 : (trace.ffloor->flags & FF_LOWERTEXTURE) ? 2 : 1; + outdata->HitTexture = trace.ffloor->master->sidedef[0]->textures[txpart].texture; + break; + } + default: + break; + } + outdata->HitLocation = trace.HitPos; + outdata->Distance = trace.Distance; + outdata->NumPortals = TData.NumPortals; + outdata->HitType = trace.HitType; + } + return ret; +} + +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitActor); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitLine); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitSector); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, Hit3DFloor); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitTexture); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitLocation); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, Distance); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, NumPortals); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, LineSide); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, LinePart); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, SectorPlane); +DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitType); + +DEFINE_ACTION_FUNCTION(AActor, LineTrace) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_ANGLE(angle); + PARAM_FLOAT(distance); + PARAM_ANGLE(pitch); + PARAM_INT_DEF(flags); + PARAM_FLOAT_DEF(offsetz); + PARAM_FLOAT_DEF(offsetforward); + PARAM_FLOAT_DEF(offsetside); + PARAM_POINTER_DEF(data, FLineTraceData); + ACTION_RETURN_BOOL(P_LineTrace(self,angle,distance,pitch,flags,offsetz,offsetforward,offsetside,data)); +} + //========================================================================== // // P_LinePickActor diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 4d61435a6..dbea3fd47 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -29,6 +29,32 @@ struct FCheckPosition native void ClearLastRipped(); } +struct FLineTraceData +{ + enum ETraceResult + { + TRACE_HitNone, + TRACE_HitFloor, + TRACE_HitCeiling, + TRACE_HitWall, + TRACE_HitActor, + TRACE_CrossingPortal + }; + + Actor HitActor; + Line HitLine; + Sector HitSector; + F3DFloor Hit3DFloor; + TextureID HitTexture; + Vector3 HitLocation; + double Distance; + int NumPortals; + int LineSide; + int LinePart; + int SectorPlane; + int HitType; +} + struct LinkContext { voidptr sector_list; // really msecnode but that's not exported yet. @@ -602,6 +628,7 @@ class Actor : Thinker native native void PoisonMobj (Actor inflictor, Actor source, int damage, int duration, int period, Name type); native double AimLineAttack(double angle, double distance, out FTranslatedLineTarget pLineTarget = null, double vrange = 0., int flags = 0, Actor target = null, Actor friender = null); 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 bool IsVisible(Actor other, bool allaround, LookExParams params = null); native bool HitFriend(); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index e6954b789..47cf4accd 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -897,6 +897,18 @@ enum ELineAttackFlags LAF_ABSPOSITION = 1 << 7, } +enum ELineTraceFlags +{ + TRF_ABSPOSITION = 1, + TRF_ABSOFFSET = 2, + TRF_THRUSPECIES = 4, + TRF_THRUACTORS = 8, + TRF_THRUBLOCK = 16, + TRF_THRUHITSCAN = 32, + TRF_NOSKY = 64, + TRF_ALLACTORS = 128, +} + const DEFMELEERANGE = 64; const SAWRANGE = (64.+(1./65536.)); // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states) const MISSILERANGE = (32*64);