mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-11 07:12:16 +00:00
- added portal-awareness to the railgun trail.
This required some changes to the Trace function because it turned out that the original was incapable of collecting the required information: * actors are now also linked into blockmap blocks on both sides if they occupy the boundary of a sector portal. * Trace will no longer set up parallel traces in all parts connected with sector portal, but only use one trace and relocate that on the actual boundary.
This commit is contained in:
parent
eb30bf6e14
commit
0f6a567055
8 changed files with 291 additions and 308 deletions
182
src/p_effect.cpp
182
src/p_effect.cpp
|
@ -621,19 +621,65 @@ void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, in
|
|||
}
|
||||
}
|
||||
|
||||
void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &portalhits, const DVector3 &end, int color1, int color2, double maxdiff_d, int flags, PClassActor *spawnclass, DAngle angle, int duration, double sparsity, double drift, int SpiralOffset)
|
||||
struct TrailSegment
|
||||
{
|
||||
double length, lengthsquared;
|
||||
DVector3 start;
|
||||
DVector3 dir;
|
||||
DVector3 extend;
|
||||
DVector2 soundpos;
|
||||
double length;
|
||||
double sounddist;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1, int color2, double maxdiff, int flags, PClassActor *spawnclass, DAngle angle, int duration, double sparsity, double drift, int SpiralOffset)
|
||||
{
|
||||
double length = 0;
|
||||
int steps, i;
|
||||
TArray<TrailSegment> trail;
|
||||
TAngle<double> deg;
|
||||
DVector3 step, dir, pos, extend;
|
||||
DVector3 pos;
|
||||
bool fullbright;
|
||||
float maxdiff = (float)maxdiff_d;
|
||||
unsigned segment;
|
||||
double lencount;
|
||||
|
||||
for (unsigned i = 0; i < portalhits.Size() - 1; i++)
|
||||
{
|
||||
TrailSegment seg;
|
||||
|
||||
seg.start = portalhits[i].ContPos;
|
||||
seg.dir = portalhits[i].OutDir;
|
||||
seg.length = (portalhits[i + 1].HitPos - seg.start).Length();
|
||||
|
||||
//Calculate PerpendicularVector (extend, dir):
|
||||
double minelem = 1;
|
||||
int epos;
|
||||
int ii;
|
||||
for (epos = 0, ii = 0; ii < 3; ++ii)
|
||||
{
|
||||
if (fabs(seg.dir[ii]) < minelem)
|
||||
{
|
||||
epos = ii;
|
||||
minelem = fabs(seg.dir[ii]);
|
||||
}
|
||||
}
|
||||
DVector3 tempvec(0, 0, 0);
|
||||
tempvec[epos] = 1;
|
||||
seg.extend = (tempvec - (seg.dir | tempvec) * seg.dir) * 3;
|
||||
length += seg.length;
|
||||
|
||||
// Only consider sound in 2D (for now, anyway)
|
||||
// [BB] You have to divide by lengthsquared here, not multiply with it.
|
||||
AActor *mo = players[consoleplayer].camera;
|
||||
|
||||
double r = ((seg.start.Y - mo->Y()) * (-seg.dir.Y) - (seg.start.X - mo->X()) * (seg.dir.X)) / (seg.length * seg.length);
|
||||
r = clamp<double>(r, 0., 1.);
|
||||
seg.soundpos = seg.start + r * seg.dir;
|
||||
seg.sounddist = (seg.soundpos - mo->Pos()).LengthSquared();
|
||||
trail.Push(seg);
|
||||
}
|
||||
|
||||
dir = end - start;
|
||||
lengthsquared = dir | dir;
|
||||
length = g_sqrt(lengthsquared);
|
||||
steps = xs_FloorToInt(length / 3);
|
||||
fullbright = !!(flags & RAF_FULLBRIGHT);
|
||||
|
||||
|
@ -652,30 +698,19 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
|
|||
// The railgun's sound is special. It gets played from the
|
||||
// point on the slug's trail that is closest to the hearing player.
|
||||
AActor *mo = players[consoleplayer].camera;
|
||||
DVector3 point;
|
||||
double r;
|
||||
double dirz;
|
||||
|
||||
if (fabs(mo->X() - start.X) < 20
|
||||
&& fabs(mo->Y() - start.Y) < 20)
|
||||
if (fabs(mo->X() - trail[0].start.X) < 20 && fabs(mo->Y() - trail[0].start.Y) < 20)
|
||||
{ // This player (probably) fired the railgun
|
||||
S_Sound (mo, CHAN_WEAPON, sound, 1, ATTN_NORM);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Only consider sound in 2D (for now, anyway)
|
||||
// [BB] You have to divide by lengthsquared here, not multiply with it.
|
||||
|
||||
r = ((start.Y - mo->Y()) * (-dir.Y) - (start.X - mo->X()) * (dir.X)) / lengthsquared;
|
||||
r = clamp<double>(r, 0., 1.);
|
||||
|
||||
dirz = dir.Z;
|
||||
dir.Z = 0;
|
||||
point = start + r * dir;
|
||||
dir.Z = dirz;
|
||||
|
||||
S_Sound (DVector3(point.X, point.Y, ViewPos.Z), CHAN_WEAPON, sound, 1, ATTN_NORM);
|
||||
TrailSegment *shortest = NULL;
|
||||
for (auto &seg : trail)
|
||||
{
|
||||
if (shortest == NULL || shortest->sounddist > seg.sounddist) shortest = &seg;
|
||||
}
|
||||
S_Sound (DVector3(shortest->soundpos, ViewPos.Z), CHAN_WEAPON, sound, 1, ATTN_NORM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -685,35 +720,16 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
|
|||
return;
|
||||
}
|
||||
|
||||
dir /= length;
|
||||
|
||||
//Calculate PerpendicularVector (extend, dir):
|
||||
double minelem = 1;
|
||||
int epos;
|
||||
for (epos = 0, i = 0; i < 3; ++i)
|
||||
{
|
||||
if (fabs(dir[i]) < minelem)
|
||||
{
|
||||
epos = i;
|
||||
minelem = fabs(dir[i]);
|
||||
}
|
||||
}
|
||||
DVector3 tempvec(0, 0, 0);
|
||||
tempvec[epos] = 1;
|
||||
extend = tempvec - (dir | tempvec) * dir;
|
||||
//
|
||||
|
||||
extend *= 3;
|
||||
step = dir * 3;
|
||||
|
||||
// Create the outer spiral.
|
||||
if (color1 != -1 && (!r_rail_smartspiral || color2 == -1) && r_rail_spiralsparsity > 0 && (spawnclass == NULL))
|
||||
{
|
||||
DVector3 spiral_step = step * r_rail_spiralsparsity * sparsity;
|
||||
double stepsize = 3 * r_rail_spiralsparsity * sparsity;
|
||||
int spiral_steps = (int)(steps * r_rail_spiralsparsity / sparsity);
|
||||
segment = 0;
|
||||
lencount = trail[0].length;
|
||||
|
||||
color1 = color1 == 0 ? -1 : ParticleColor(color1);
|
||||
pos = start;
|
||||
pos = trail[0].start;
|
||||
deg = (double)SpiralOffset;
|
||||
for (i = spiral_steps; i; i--)
|
||||
{
|
||||
|
@ -731,12 +747,12 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
|
|||
p->size = 3;
|
||||
p->bright = fullbright;
|
||||
|
||||
tempvec = DMatrix3x3(dir, deg) * extend;
|
||||
tempvec = DMatrix3x3(trail[segment].dir, deg) * trail[segment].extend;
|
||||
p->Vel = tempvec * drift / 16.;
|
||||
p->Pos = tempvec + pos;
|
||||
pos += spiral_step;
|
||||
pos += trail[segment].dir * stepsize;
|
||||
deg += double(r_rail_spiralsparsity * 14);
|
||||
|
||||
lencount -= stepsize;
|
||||
if (color1 == -1)
|
||||
{
|
||||
int rand = M_Random();
|
||||
|
@ -754,19 +770,36 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
|
|||
{
|
||||
p->color = color1;
|
||||
}
|
||||
|
||||
if (lencount <= 0)
|
||||
{
|
||||
segment++;
|
||||
if (segment < trail.Size())
|
||||
{
|
||||
pos = trail[segment].start - trail[segment].dir * lencount;
|
||||
lencount += trail[segment].length;
|
||||
}
|
||||
else
|
||||
{
|
||||
// should never happen but if something goes wrong, just terminate the loop.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the inner trail.
|
||||
if (color2 != -1 && r_rail_trailsparsity > 0 && spawnclass == NULL)
|
||||
{
|
||||
DVector3 trail_step = step * r_rail_trailsparsity * sparsity;
|
||||
double stepsize = 3 * r_rail_spiralsparsity * sparsity;
|
||||
int trail_steps = xs_FloorToInt(steps * r_rail_trailsparsity / sparsity);
|
||||
|
||||
color2 = color2 == 0 ? -1 : ParticleColor(color2);
|
||||
DVector3 diff(0, 0, 0);
|
||||
|
||||
pos = start;
|
||||
pos = trail[0].start;
|
||||
lencount = trail[0].length;
|
||||
segment = 0;
|
||||
for (i = trail_steps; i; i--)
|
||||
{
|
||||
// [XA] inner trail uses a different default duration (33).
|
||||
|
@ -793,8 +826,8 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
|
|||
p->Pos = postmp;
|
||||
if (color1 != -1)
|
||||
p->Acc.Z -= 1./4096;
|
||||
pos += trail_step;
|
||||
|
||||
pos += trail[segment].dir * stepsize;
|
||||
lencount -= stepsize;
|
||||
p->bright = fullbright;
|
||||
|
||||
if (color2 == -1)
|
||||
|
@ -812,6 +845,21 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
|
|||
{
|
||||
p->color = color2;
|
||||
}
|
||||
if (lencount <= 0)
|
||||
{
|
||||
segment++;
|
||||
if (segment < trail.Size())
|
||||
{
|
||||
pos = trail[segment].start - trail[segment].dir * lencount;
|
||||
lencount += trail[segment].length;
|
||||
}
|
||||
else
|
||||
{
|
||||
// should never happen but if something goes wrong, just terminate the loop.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// create actors
|
||||
|
@ -820,11 +868,14 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
|
|||
if (sparsity < 1)
|
||||
sparsity = 32;
|
||||
|
||||
DVector3 trail_step = (step / 3) * sparsity;
|
||||
double stepsize = 3 * r_rail_spiralsparsity * sparsity;
|
||||
int trail_steps = (int)((steps * 3) / sparsity);
|
||||
DVector3 diff(0, 0, 0);
|
||||
|
||||
pos = start;
|
||||
pos = trail[0].start;
|
||||
lencount = trail[0].length;
|
||||
segment = 0;
|
||||
|
||||
for (i = trail_steps; i; i--)
|
||||
{
|
||||
if (maxdiff > 0)
|
||||
|
@ -840,7 +891,22 @@ void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &
|
|||
AActor *thing = Spawn (spawnclass, pos + diff, ALLOW_REPLACE);
|
||||
if (thing)
|
||||
thing->Angles.Yaw = angle;
|
||||
pos += trail_step;
|
||||
pos += trail[segment].dir * stepsize;
|
||||
lencount -= stepsize;
|
||||
if (lencount <= 0)
|
||||
{
|
||||
segment++;
|
||||
if (segment < trail.Size())
|
||||
{
|
||||
pos = trail[segment].start - trail[segment].dir * lencount;
|
||||
lencount += trail[segment].length;
|
||||
}
|
||||
else
|
||||
{
|
||||
// should never happen but if something goes wrong, just terminate the loop.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ struct SPortalHit
|
|||
DVector3 OutDir;
|
||||
};
|
||||
|
||||
void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray<SPortalHit> &portalhits, const DVector3 &end, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = 0., int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270);
|
||||
void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1, int color2, double maxdiff = 0, int flags = 0, PClassActor *spawnclass = NULL, DAngle angle = 0., int duration = 35, double sparsity = 1.0, double drift = 1.0, int SpiralOffset = 270);
|
||||
void P_DrawSplash (int count, const DVector3 &pos, DAngle angle, int kind);
|
||||
void P_DrawSplash2 (int count, const DVector3 &pos, DAngle angle, int updown, int kind);
|
||||
void P_DisconnectEffect (AActor *actor);
|
||||
|
|
|
@ -4598,15 +4598,8 @@ void P_RailAttack(FRailParams *p)
|
|||
rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true;
|
||||
rail_data.ThruSpecies = (puffDefaults->flags6 & MF6_MTHRUSPECIES) ? true : false;
|
||||
|
||||
// to make things easier, push the start position and directional vector onto the PortalHits array as its first element
|
||||
SPortalHit phit = { start, start, vec };
|
||||
rail_data.PortalHits.Push(phit);
|
||||
Trace(start, source->Sector, vec, p->distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data);
|
||||
|
||||
// and push the hit position, too, so that the array contains the entire trace with all transition points.
|
||||
phit = { trace.HitPos, trace.HitPos, trace.HitVector };
|
||||
rail_data.PortalHits.Push(phit);
|
||||
|
||||
// Hurt anything the trace hit
|
||||
unsigned int i;
|
||||
FName damagetype = (puffDefaults == NULL || puffDefaults->DamageType == NAME_None) ? FName(NAME_Railgun) : puffDefaults->DamageType;
|
||||
|
@ -4709,7 +4702,7 @@ void P_RailAttack(FRailParams *p)
|
|||
}
|
||||
|
||||
// Draw the slug's trail.
|
||||
P_DrawRailTrail(source, start, rail_data.PortalHits, trace.HitPos, p->color1, p->color2, p->maxdiff, p->flags, p->spawnclass, angle, p->duration, p->sparsity, p->drift, p->SpiralOffset);
|
||||
P_DrawRailTrail(source, rail_data.PortalHits, p->color1, p->color2, p->maxdiff, p->flags, p->spawnclass, angle, p->duration, p->sparsity, p->drift, p->SpiralOffset);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -450,13 +450,13 @@ void AActor::LinkToWorld(bool spawningmapthing, sector_t *sector)
|
|||
// link into blockmap (inert things don't need to be in the blockmap)
|
||||
if (!(flags & MF_NOBLOCKMAP))
|
||||
{
|
||||
FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals);
|
||||
FPortalGroupArray check;
|
||||
|
||||
P_CollectConnectedGroups(Sector->PortalGroup, Pos(), Top(), radius, check);
|
||||
|
||||
for (int i = -1; i < (int)check.Size(); i++)
|
||||
{
|
||||
DVector3 pos = i==-1? Pos() : PosRelative(check[i]);
|
||||
DVector3 pos = i==-1? Pos() : PosRelative(check[i] & ~FPortalGroupArray::FLAT);
|
||||
|
||||
int x1 = GetBlockX(pos.X - radius);
|
||||
int x2 = GetBlockX(pos.X + radius);
|
||||
|
@ -1616,12 +1616,22 @@ int FPathTraverse::PortalRelocate(intercept_t *in, int flags, DVector3 *optpos)
|
|||
P_TranslatePortalXY(in->d.line, optpos->X, optpos->Y);
|
||||
P_TranslatePortalZ(in->d.line, optpos->Z);
|
||||
}
|
||||
line_t *saved = in->d.line; // this gets overwriitten by the init call.
|
||||
line_t *saved = in->d.line; // this gets overwritten by the init call.
|
||||
intercepts.Resize(intercept_index);
|
||||
init(hitx, hity, endx, endy, flags, in->frac);
|
||||
init(hitx, hity, endx, endy, flags, in->frac + EQUAL_EPSILON);
|
||||
return saved->getPortal()->mType == PORTT_LINKED? 1:-1;
|
||||
}
|
||||
|
||||
void FPathTraverse::PortalRelocate(AActor *portalthing, int flags, double hitfrac)
|
||||
{
|
||||
double hitx = trace.x + portalthing->Scale.X;
|
||||
double hity = trace.y + portalthing->Scale.Y;
|
||||
double endx = hitx + trace.dx;
|
||||
double endy = hity + trace.dy;
|
||||
intercepts.Resize(intercept_index);
|
||||
init(hitx, hity, endx, endy, flags, hitfrac);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -373,6 +373,7 @@ public:
|
|||
}
|
||||
void init(double x1, double y1, double x2, double y2, int flags, double startfrac = 0);
|
||||
int PortalRelocate(intercept_t *in, int flags, DVector3 *optpos = NULL);
|
||||
void PortalRelocate(AActor *portalthing, int flags, double hitfrac);
|
||||
virtual ~FPathTraverse();
|
||||
const divline_t &Trace() const { return trace; }
|
||||
|
||||
|
|
366
src/p_trace.cpp
366
src/p_trace.cpp
|
@ -55,7 +55,6 @@ struct FTraceInfo
|
|||
DWORD WallMask;
|
||||
AActor *IgnoreThis;
|
||||
FTraceResults *Results;
|
||||
FTraceResults *TempResults;
|
||||
sector_t *CurSector;
|
||||
double MaxDist;
|
||||
double EnterDist;
|
||||
|
@ -64,10 +63,8 @@ struct FTraceInfo
|
|||
DWORD TraceFlags;
|
||||
int inshootthrough;
|
||||
double startfrac;
|
||||
int aimdir;
|
||||
double limitz;
|
||||
double lastfloorportalheight;
|
||||
double lastceilingportalheight;
|
||||
int ptflags;
|
||||
|
||||
// These are required for 3D-floor checking
|
||||
// to create a fake sector with a floor
|
||||
|
@ -76,12 +73,12 @@ struct FTraceInfo
|
|||
int sectorsel;
|
||||
|
||||
void Setup3DFloors();
|
||||
bool LineCheck(intercept_t *in);
|
||||
bool ThingCheck(intercept_t *in);
|
||||
bool LineCheck(intercept_t *in, double dist, DVector3 hit);
|
||||
bool ThingCheck(intercept_t *in, double dist, DVector3 hit);
|
||||
bool TraceTraverse (int ptflags);
|
||||
bool CheckPlane(const secplane_t &plane);
|
||||
int EnterLinePortal(line_t *li, double frac);
|
||||
void EnterSectorPortal(int position, double frac, sector_t *entersec);
|
||||
void EnterLinePortal(FPathTraverse &pt, intercept_t *in);
|
||||
void EnterSectorPortal(FPathTraverse &pt, int position, double frac, sector_t *entersec);
|
||||
|
||||
|
||||
bool CheckSectorPlane(const sector_t *sector, bool checkFloor)
|
||||
|
@ -107,6 +104,38 @@ struct FTraceInfo
|
|||
static bool EditTraceResult (DWORD flags, FTraceResults &res);
|
||||
|
||||
|
||||
|
||||
static void GetPortalTransition(DVector3 &pos, sector_t *&sec)
|
||||
{
|
||||
bool moved = false;
|
||||
double testz = pos.Z;
|
||||
|
||||
while (!sec->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
AActor *port = sec->SkyBoxes[sector_t::ceiling];
|
||||
if (pos.Z > port->specialf1)
|
||||
{
|
||||
pos += port->Scale;
|
||||
sec = P_PointInSector(pos);
|
||||
moved = true;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (!moved)
|
||||
{
|
||||
while (!sec->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
AActor *port = sec->SkyBoxes[sector_t::floor];
|
||||
if (pos.Z <= port->specialf1)
|
||||
{
|
||||
pos += port->Scale;
|
||||
sec = P_PointInSector(pos);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Trace entry point
|
||||
|
@ -117,16 +146,15 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
|
|||
ActorFlags actorMask, DWORD wallMask, AActor *ignore, FTraceResults &res, DWORD flags,
|
||||
ETraceStatus(*callback)(FTraceResults &res, void *), void *callbackdata)
|
||||
{
|
||||
int ptflags;
|
||||
FTraceInfo inf;
|
||||
FTraceResults tempResult;
|
||||
|
||||
memset(&tempResult, 0, sizeof(tempResult));
|
||||
tempResult.Fraction = tempResult.Distance = NO_VALUE;
|
||||
|
||||
ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
|
||||
|
||||
inf.Start = start;
|
||||
GetPortalTransition(inf.Start, sector);
|
||||
inf.ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES;
|
||||
inf.Vec = direction;
|
||||
inf.ActorMask = actorMask;
|
||||
inf.WallMask = wallMask;
|
||||
|
@ -138,15 +166,30 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
|
|||
inf.TraceCallbackData = callbackdata;
|
||||
inf.TraceFlags = flags;
|
||||
inf.Results = &res;
|
||||
inf.TempResults = &tempResult;
|
||||
inf.inshootthrough = true;
|
||||
inf.sectorsel=0;
|
||||
inf.aimdir = -1;
|
||||
inf.startfrac = 0;
|
||||
inf.lastfloorportalheight = inf.lastceilingportalheight = start.Z;
|
||||
inf.limitz = inf.Start.Z;
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
if (inf.TraceTraverse (ptflags))
|
||||
if ((flags & TRACE_ReportPortals) && callback != NULL)
|
||||
{
|
||||
tempResult.HitType = TRACE_CrossingPortal;
|
||||
tempResult.HitPos = tempResult.SrcFromTarget = inf.Start;
|
||||
tempResult.HitVector = inf.Vec;
|
||||
callback(tempResult, inf.TraceCallbackData);
|
||||
}
|
||||
bool reslt = inf.TraceTraverse(inf.ptflags);
|
||||
|
||||
if ((flags & TRACE_ReportPortals) && callback != NULL)
|
||||
{
|
||||
tempResult.HitType = TRACE_CrossingPortal;
|
||||
tempResult.HitPos = tempResult.SrcFromTarget = inf.Results->HitPos;
|
||||
tempResult.HitVector = inf.Vec;
|
||||
callback(tempResult, inf.TraceCallbackData);
|
||||
}
|
||||
|
||||
if (reslt)
|
||||
{
|
||||
return flags ? EditTraceResult(flags, res) : true;
|
||||
}
|
||||
|
@ -163,48 +206,32 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d
|
|||
//
|
||||
//============================================================================
|
||||
|
||||
void FTraceInfo::EnterSectorPortal(int position, double frac, sector_t *entersec)
|
||||
void FTraceInfo::EnterSectorPortal(FPathTraverse &pt, int position, double frac, sector_t *entersec)
|
||||
{
|
||||
if (aimdir != -1 && aimdir != position) return;
|
||||
AActor *portal = entersec->SkyBoxes[position];
|
||||
|
||||
if (aimdir == sector_t::ceiling && portal->specialf1 < limitz) return;
|
||||
else if (aimdir == sector_t::floor && portal->specialf1 > limitz) return;
|
||||
|
||||
FTraceInfo newtrace;
|
||||
FTraceResults results;
|
||||
|
||||
memset(&results, 0, sizeof(results));
|
||||
|
||||
newtrace.Start += portal->Scale;
|
||||
|
||||
frac += 1 / MaxDist;
|
||||
double enterdist = MaxDist * frac;
|
||||
DVector2 enter = newtrace.Start.XY() + enterdist * Vec.XY();
|
||||
DVector3 exit = Start + enterdist * Vec;
|
||||
DVector3 enter = exit + portal->Scale;
|
||||
|
||||
newtrace.Vec = Vec;
|
||||
newtrace.ActorMask = ActorMask;
|
||||
newtrace.WallMask = WallMask;
|
||||
newtrace.IgnoreThis = IgnoreThis;
|
||||
newtrace.Results = &results;
|
||||
newtrace.TempResults = TempResults;
|
||||
newtrace.CurSector = P_PointInSector(enter);
|
||||
newtrace.MaxDist = MaxDist;
|
||||
newtrace.EnterDist = EnterDist;
|
||||
newtrace.TraceCallback = TraceCallback;
|
||||
newtrace.TraceCallbackData = TraceCallbackData;
|
||||
newtrace.TraceFlags = TraceFlags;
|
||||
newtrace.inshootthrough = true;
|
||||
newtrace.startfrac = frac;
|
||||
newtrace.aimdir = position;
|
||||
newtrace.limitz = portal->specialf1;
|
||||
newtrace.sectorsel = 0;
|
||||
newtrace.lastfloorportalheight = newtrace.lastceilingportalheight = limitz;
|
||||
Start += portal->Scale;
|
||||
CurSector = P_PointInSector(enter);
|
||||
inshootthrough = true;
|
||||
startfrac = frac;
|
||||
EnterDist = enterdist;
|
||||
pt.PortalRelocate(portal, ptflags, frac);
|
||||
|
||||
if (newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES))
|
||||
if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
|
||||
{
|
||||
TempResults->CopyIfCloser(newtrace.Results);
|
||||
enterdist = MaxDist * frac;
|
||||
Results->HitType = TRACE_CrossingPortal;
|
||||
Results->HitPos = exit;
|
||||
Results->SrcFromTarget = enter;
|
||||
Results->HitVector = Vec;
|
||||
TraceCallback(*Results, TraceCallbackData);
|
||||
}
|
||||
|
||||
Setup3DFloors();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
@ -213,59 +240,38 @@ void FTraceInfo::EnterSectorPortal(int position, double frac, sector_t *entersec
|
|||
//
|
||||
//============================================================================
|
||||
|
||||
int FTraceInfo::EnterLinePortal(line_t *li, double frac)
|
||||
void FTraceInfo::EnterLinePortal(FPathTraverse &pt, intercept_t *in)
|
||||
{
|
||||
line_t *li = in->d.line;
|
||||
FLinePortal *port = li->getPortal();
|
||||
|
||||
// The caller cannot handle portals without global offset.
|
||||
if (port->mType != PORTT_LINKED && (TraceFlags & TRACE_PortalRestrict)) return -1;
|
||||
|
||||
FTraceInfo newtrace;
|
||||
|
||||
newtrace.Start = Start;
|
||||
newtrace.Vec = Vec;
|
||||
|
||||
P_TranslatePortalXY(li, newtrace.Start.X, newtrace.Start.Y);
|
||||
P_TranslatePortalZ(li, newtrace.Start.Z);
|
||||
P_TranslatePortalVXVY(li, newtrace.Vec.X, newtrace.Vec.Y);
|
||||
|
||||
frac += 1 / MaxDist;
|
||||
double frac = in->frac + EQUAL_EPSILON;
|
||||
double enterdist = MaxDist * frac;
|
||||
DVector3 enter = newtrace.Start + enterdist * Vec;
|
||||
DVector3 exit = Start + MaxDist * in->frac * Vec;
|
||||
|
||||
newtrace.ActorMask = ActorMask;
|
||||
newtrace.WallMask = WallMask;
|
||||
newtrace.IgnoreThis = IgnoreThis;
|
||||
newtrace.Results = Results;
|
||||
newtrace.TempResults = TempResults;
|
||||
newtrace.CurSector = P_PointInSector(enter);
|
||||
newtrace.MaxDist = MaxDist;
|
||||
newtrace.EnterDist = EnterDist;
|
||||
newtrace.TraceCallback = TraceCallback;
|
||||
newtrace.TraceCallbackData = TraceCallbackData;
|
||||
newtrace.TraceFlags = TraceFlags;
|
||||
newtrace.inshootthrough = true;
|
||||
newtrace.startfrac = frac;
|
||||
newtrace.aimdir = aimdir;
|
||||
newtrace.limitz = limitz;
|
||||
P_TranslatePortalXY(li, Start.X, Start.Y);
|
||||
P_TranslatePortalZ(li, Start.Z);
|
||||
P_TranslatePortalVXVY(li, Vec.X, Vec.Y);
|
||||
P_TranslatePortalZ(li, limitz);
|
||||
|
||||
P_TranslatePortalZ(li, newtrace.limitz);
|
||||
newtrace.lastfloorportalheight = newtrace.lastceilingportalheight = newtrace.limitz;
|
||||
newtrace.sectorsel = 0;
|
||||
Results->unlinked = true;
|
||||
CurSector = P_PointInSector(Start + enterdist * Vec);
|
||||
EnterDist = enterdist;
|
||||
inshootthrough = true;
|
||||
startfrac = frac;
|
||||
Results->unlinked |= (port->mType != PORTT_LINKED);
|
||||
pt.PortalRelocate(in, ptflags);
|
||||
|
||||
if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL)
|
||||
{
|
||||
enterdist = MaxDist * in->frac;
|
||||
Results->HitType = TRACE_CrossingPortal;
|
||||
Results->HitPos = enter;
|
||||
P_TranslatePortalXY(li, enter.X, enter.Y);
|
||||
P_TranslatePortalZ(li, enter.Z);
|
||||
Results->SrcFromTarget = enter;
|
||||
Results->HitVector = newtrace.Vec;
|
||||
Results->HitPos = exit;
|
||||
P_TranslatePortalXY(li, exit.X, exit.Y);
|
||||
P_TranslatePortalZ(li, exit.Z);
|
||||
Results->SrcFromTarget = exit;
|
||||
Results->HitVector = Vec;
|
||||
TraceCallback(*Results, TraceCallbackData);
|
||||
}
|
||||
|
||||
return newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -355,14 +361,6 @@ void FTraceInfo::Setup3DFloors()
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!CurSector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
EnterSectorPortal(sector_t::ceiling, startfrac, CurSector);
|
||||
}
|
||||
if (!CurSector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
EnterSectorPortal(sector_t::floor, startfrac, CurSector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -372,14 +370,11 @@ void FTraceInfo::Setup3DFloors()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FTraceInfo::LineCheck(intercept_t *in)
|
||||
bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit)
|
||||
{
|
||||
int lineside;
|
||||
sector_t *entersector;
|
||||
|
||||
double dist = MaxDist * in->frac;
|
||||
DVector3 hit = Start + Vec * dist;
|
||||
|
||||
double ff, fc, bf = 0, bc = 0;
|
||||
|
||||
if (in->d.line->frontsector->sectornum == CurSector->sectornum)
|
||||
|
@ -454,78 +449,15 @@ bool FTraceInfo::LineCheck(intercept_t *in)
|
|||
|
||||
if (hit.Z <= ff)
|
||||
{
|
||||
if (CurSector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
// hit floor in front of wall
|
||||
Results->HitType = TRACE_HitFloor;
|
||||
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((TraceFlags & TRACE_ReportPortals) && lastfloorportalheight > fc)
|
||||
{
|
||||
lastfloorportalheight = fc;
|
||||
if (TraceCallback != NULL)
|
||||
{
|
||||
Results->HitType = TRACE_CrossingPortal;
|
||||
double hitz = CurSector->SkyBoxes[sector_t::floor]->specialf1;
|
||||
Results->HitPos = Start + Vec * (hitz - Start.Z) / Vec.Z;
|
||||
Results->SrcFromTarget = Results->HitPos + CurSector->SkyBoxes[sector_t::floor]->Scale;
|
||||
Results->HitVector = Vec;
|
||||
TraceCallback(*Results, TraceCallbackData);
|
||||
}
|
||||
}
|
||||
if (entersector == NULL || entersector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
// hit beyond a portal plane. This needs to be taken care of by the trace spawned on the other side.
|
||||
Results->HitType = TRACE_HitNone;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// hit floor in front of wall
|
||||
Results->HitType = TRACE_HitFloor;
|
||||
Results->HitTexture = CurSector->GetTexture(sector_t::floor);
|
||||
}
|
||||
else if (hit.Z >= fc)
|
||||
{
|
||||
if (CurSector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
// hit ceiling in front of wall
|
||||
Results->HitType = TRACE_HitCeiling;
|
||||
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((TraceFlags & TRACE_ReportPortals) && lastceilingportalheight < fc)
|
||||
{
|
||||
lastceilingportalheight = fc;
|
||||
if (TraceCallback != NULL)
|
||||
{
|
||||
Results->HitType = TRACE_CrossingPortal;
|
||||
double hitz = CurSector->SkyBoxes[sector_t::ceiling]->specialf1;
|
||||
Results->HitPos = Start + Vec * (hitz - Start.Z) / Vec.Z;
|
||||
Results->SrcFromTarget = Results->HitPos + CurSector->SkyBoxes[sector_t::ceiling]->Scale;
|
||||
Results->HitVector = Vec;
|
||||
TraceCallback(*Results, TraceCallbackData);
|
||||
}
|
||||
}
|
||||
if (entersector == NULL || entersector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
// hit beyond a portal plane. This needs to be taken care of by the trace spawned on the other side.
|
||||
Results->HitType = TRACE_HitNone;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (in->d.line->isLinePortal())
|
||||
{
|
||||
if (entersector == NULL || (hit.Z >= bf && hit.Z <= bc))
|
||||
{
|
||||
int res = EnterLinePortal(in->d.line, in->frac);
|
||||
if (res != -1)
|
||||
{
|
||||
aimdir = INT_MAX; // flag for ending the traverse
|
||||
return !!res;
|
||||
}
|
||||
}
|
||||
goto normalline; // hit upper or lower tier.
|
||||
// hit ceiling in front of wall
|
||||
Results->HitType = TRACE_HitCeiling;
|
||||
Results->HitTexture = CurSector->GetTexture(sector_t::ceiling);
|
||||
}
|
||||
else if (entersector == NULL ||
|
||||
hit.Z < bf || hit.Z > bc ||
|
||||
|
@ -610,15 +542,6 @@ normalline:
|
|||
// we need to as well, for compatibility
|
||||
P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact);
|
||||
}
|
||||
|
||||
if (!entersector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
EnterSectorPortal(sector_t::ceiling, in->frac, entersector);
|
||||
}
|
||||
if (!entersector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
EnterSectorPortal(sector_t::floor, in->frac, entersector);
|
||||
}
|
||||
}
|
||||
cont:
|
||||
|
||||
|
@ -696,11 +619,8 @@ cont:
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FTraceInfo::ThingCheck(intercept_t *in)
|
||||
bool FTraceInfo::ThingCheck(intercept_t *in, double dist, DVector3 hit)
|
||||
{
|
||||
double dist = MaxDist * in->frac;
|
||||
DVector3 hit = Start + Vec * dist;
|
||||
|
||||
if (hit.Z > in->d.thing->Top())
|
||||
{
|
||||
// trace enters above actor
|
||||
|
@ -834,49 +754,59 @@ bool FTraceInfo::TraceTraverse (int ptflags)
|
|||
lastsplashsector = CurSector->sectornum;
|
||||
}
|
||||
|
||||
// We have something closer in the storage for portal subtraces.
|
||||
if (TempResults->HitType != TRACE_HitNone && in->frac > TempResults->Fraction)
|
||||
double dist = MaxDist * in->frac;
|
||||
DVector3 hit = Start + Vec * dist;
|
||||
|
||||
// Crossed a floor portal?
|
||||
if (Vec.Z < 0 && !CurSector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
break;
|
||||
// calculate position where the portal is crossed
|
||||
double portz = CurSector->SkyBoxes[sector_t::floor]->specialf1;
|
||||
if (hit.Z < portz && limitz > portz)
|
||||
{
|
||||
limitz = portz;
|
||||
EnterSectorPortal(it, sector_t::floor, (portz - Start.Z) / (Vec.Z * MaxDist), CurSector);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (in->isaline)
|
||||
// ... or a ceiling portal?
|
||||
else if (Vec.Z > 0 && !CurSector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
bool res = LineCheck(in);
|
||||
if (aimdir == INT_MAX) return res; // signal for immediate abort
|
||||
if (!res) break;
|
||||
// calculate position where the portal is crossed
|
||||
double portz = CurSector->SkyBoxes[sector_t::ceiling]->specialf1;
|
||||
if (hit.Z > portz && limitz < portz)
|
||||
{
|
||||
limitz = portz;
|
||||
EnterSectorPortal(it, sector_t::ceiling, (portz - Start.Z) / (Vec.Z * MaxDist), CurSector);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (in->isaline)
|
||||
{
|
||||
if (in->d.line->isLinePortal() && P_PointOnLineSidePrecise(Start, in->d.line) == 0)
|
||||
{
|
||||
sector_t *entersector = in->d.line->backsector;
|
||||
if (entersector == NULL || (hit.Z >= entersector->floorplane.ZatPoint(hit) && hit.Z <= entersector->ceilingplane.ZatPoint(hit)))
|
||||
{
|
||||
FLinePortal *port = in->d.line->getPortal();
|
||||
// The caller cannot handle portals without global offset.
|
||||
if (port->mType == PORTT_LINKED || !(TraceFlags & TRACE_PortalRestrict))
|
||||
{
|
||||
EnterLinePortal(it, in);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!LineCheck(in, dist, hit)) break;
|
||||
}
|
||||
else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis)
|
||||
{
|
||||
if (!ThingCheck(in)) break;
|
||||
if (!ThingCheck(in, dist, hit)) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if one subtrace through a portal yielded a better result.
|
||||
if (TempResults->HitType != TRACE_HitNone &&
|
||||
(Results->HitType == TRACE_HitNone || Results->Fraction > TempResults->Fraction))
|
||||
{
|
||||
// We still need to do a water check here or this may get missed on occasion
|
||||
if (Results->CrossedWater == NULL &&
|
||||
CurSector->heightsec != NULL &&
|
||||
CurSector->heightsec->floorplane.ZatPoint(Results->HitPos) >= Results->HitPos.Z)
|
||||
{
|
||||
// Save the result so that the water check doesn't destroy it.
|
||||
FTraceResults *res = Results;
|
||||
FTraceResults hsecResult;
|
||||
Results = &hsecResult;
|
||||
|
||||
if (CheckSectorPlane(CurSector->heightsec, true))
|
||||
{
|
||||
Results->CrossedWater = §ors[CurSector->sectornum];
|
||||
Results->CrossedWaterPos = Results->HitPos;
|
||||
}
|
||||
Results = res;
|
||||
}
|
||||
|
||||
Results->CopyIfCloser(TempResults);
|
||||
return true;
|
||||
}
|
||||
else if (Results->HitType == TRACE_HitNone)
|
||||
if (Results->HitType == TRACE_HitNone)
|
||||
{
|
||||
if (CurSector->PortalBlocksMovement(sector_t::floor) && CheckSectorPlane(CurSector, true))
|
||||
{
|
||||
|
|
|
@ -87,24 +87,6 @@ struct FTraceResults
|
|||
DVector3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash
|
||||
F3DFloor *Crossed3DWater; // For 3D floor-based deep water
|
||||
DVector3 Crossed3DWaterPos;
|
||||
|
||||
void CopyIfCloser(FTraceResults *other)
|
||||
{
|
||||
if (other->Distance < Distance || HitType == TRACE_HitNone)
|
||||
{
|
||||
memcpy(this, other, myoffsetof(FTraceResults, CrossedWater));
|
||||
}
|
||||
if (CrossedWater == NULL && other->CrossedWater != NULL)
|
||||
{
|
||||
CrossedWater = other->CrossedWater;
|
||||
CrossedWaterPos = other->CrossedWaterPos;
|
||||
}
|
||||
if (Crossed3DWater == NULL && other->Crossed3DWater != NULL)
|
||||
{
|
||||
Crossed3DWater = other->Crossed3DWater;
|
||||
Crossed3DWaterPos = other->Crossed3DWaterPos;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1157,7 +1157,8 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd)
|
|||
performBlockingThrust = true;
|
||||
}
|
||||
|
||||
FBoundingBox box(mobj->X(), mobj->Y(), mobj->radius);
|
||||
DVector2 pos = mobj->PosRelative(ld);
|
||||
FBoundingBox box(pos.X, pos.Y, mobj->radius);
|
||||
|
||||
if (!box.inRange(ld) || box.BoxOnLineSide(ld) != -1)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue