A more "general purpose" line trace function. Far from a complete ZScript interface with Trace(), though.

This commit is contained in:
Marisa Kirisame 2018-01-19 00:29:49 +01:00 committed by Christoph Oelckers
parent 3f45f938d6
commit 69e8c9ec6e
5 changed files with 230 additions and 0 deletions

25
src/p_linetracedata.h Normal file
View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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<Actor> 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();

View file

@ -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);