mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
6db95182cf
9 changed files with 295 additions and 310 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; }
|
||||
|
||||
|
|
368
src/p_trace.cpp
368
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;
|
||||
double frac = in->frac + EQUAL_EPSILON;
|
||||
double enterdist = MaxDist * frac;
|
||||
DVector3 exit = Start + MaxDist * in->frac * Vec;
|
||||
|
||||
FTraceInfo newtrace;
|
||||
P_TranslatePortalXY(li, Start.X, Start.Y);
|
||||
P_TranslatePortalZ(li, Start.Z);
|
||||
P_TranslatePortalVXVY(li, Vec.X, Vec.Y);
|
||||
P_TranslatePortalZ(li, limitz);
|
||||
|
||||
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 enterdist = MaxDist / frac;
|
||||
DVector3 enter = newtrace.Start + enterdist * 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_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)
|
||||
{
|
||||
|
|
|
@ -661,10 +661,10 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy)
|
|||
if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
|
||||
}
|
||||
|
||||
FLinePortalTraverse it;
|
||||
bool repeat;
|
||||
do
|
||||
{
|
||||
FLinePortalTraverse it;
|
||||
it.init(actx, acty, dx, dy, PT_ADDLINES|PT_DELTA);
|
||||
intercept_t *in;
|
||||
|
||||
|
@ -696,6 +696,8 @@ DVector2 P_GetOffsetPosition(double x, double y, double dx, double dy)
|
|||
// update the fields, end this trace and restart from the new position
|
||||
dx = dest.X - hit.X;
|
||||
dy = dest.Y - hit.Y;
|
||||
actx = hit.X;
|
||||
acty = hit.Y;
|
||||
repeat = true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue