diff --git a/src/p_effect.cpp b/src/p_effect.cpp index db2724a02..483672f05 100644 --- a/src/p_effect.cpp +++ b/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 &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 &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 trail; TAngle 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(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 & // 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(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 & 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 & 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 & { 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 & 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 & { 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 & 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 & 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; + } + } } } } diff --git a/src/p_effect.h b/src/p_effect.h index 74df5552f..1e7750343 100644 --- a/src/p_effect.h +++ b/src/p_effect.h @@ -97,7 +97,7 @@ struct SPortalHit DVector3 OutDir; }; -void P_DrawRailTrail(AActor *source, const DVector3 &start, TArray &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 &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); diff --git a/src/p_map.cpp b/src/p_map.cpp index 76d083537..c28d3044f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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); } //========================================================================== diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 1235915c2..759ab5d6c 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -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); +} + //=========================================================================== // // diff --git a/src/p_maputl.h b/src/p_maputl.h index d53ab49a7..c22984fd4 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -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; } diff --git a/src/p_trace.cpp b/src/p_trace.cpp index bc022535f..b75fc090e 100644 --- a/src/p_trace.cpp +++ b/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)) { diff --git a/src/p_trace.h b/src/p_trace.h index 7eaf50ce5..d6132d750 100644 --- a/src/p_trace.h +++ b/src/p_trace.h @@ -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; - } - } }; diff --git a/src/po_man.cpp b/src/po_man.cpp index c025ff6c4..b6921b0d4 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -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) { diff --git a/src/portal.cpp b/src/portal.cpp index f0c5b8962..3ce45c636 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -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; }