- 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:
Christoph Oelckers 2016-04-16 19:41:33 +02:00
parent eb30bf6e14
commit 0f6a567055
8 changed files with 291 additions and 308 deletions

View file

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

View file

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

View file

@ -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);
}
//==========================================================================

View file

@ -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);
}
//===========================================================================
//
//

View file

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

View file

@ -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 = &sectors[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))
{

View file

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

View file

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