diff --git a/src/p_map.cpp b/src/p_map.cpp index 5d5777d6f..61e651ce6 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4463,10 +4463,17 @@ struct SRailHit DVector3 HitPos; DAngle HitAngle; }; +struct SPortalHit +{ + DVector3 HitPos; + DVector3 ContPos; + DVector3 OutDir; +}; struct RailData { AActor *Caller; TArray RailHits; + TArray PortalHits; bool StopAtOne; bool StopAtInvul; bool ThruSpecies; @@ -4475,6 +4482,16 @@ struct RailData static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata) { RailData *data = (RailData *)userdata; + if (res.HitType == TRACE_CrossingPortal) + { + SPortalHit newhit; + newhit.HitPos = res.HitPos; + newhit.ContPos = res.SrcFromTarget; + newhit.OutDir = res.HitVector; + data->PortalHits.Push(newhit); + return TRACE_Continue; + } + if (res.HitType != TRACE_HitActor) { return TRACE_Stop; @@ -4559,7 +4576,8 @@ void P_RailAttack(FRailParams *p) assert(puffclass != NULL); // Because we set it to a default above AActor *puffDefaults = GetDefaultByType(puffclass->GetReplacement()); //Contains all the flags such as FOILINVUL, etc. - flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? 0 : TRACE_PCross | TRACE_Impact; + // disabled because not complete yet. + flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? 0/*TRACE_ReportPortals*/ : TRACE_PCross | TRACE_Impact /*| TRACE_ReportPortals*/; rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true; rail_data.ThruSpecies = (puffDefaults->flags6 & MF6_MTHRUSPECIES) ? true : false; Trace(start, source->Sector, vec, p->distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data); diff --git a/src/p_trace.cpp b/src/p_trace.cpp index dabc92110..7526456e1 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -66,6 +66,8 @@ struct FTraceInfo double startfrac; int aimdir; double limitz; + double lastfloorportalheight; + double lastceilingportalheight; // These are required for 3D-floor checking // to create a fake sector with a floor @@ -141,6 +143,7 @@ bool Trace(const DVector3 &start, sector_t *sector, const DVector3 &direction, d inf.sectorsel=0; inf.aimdir = -1; inf.startfrac = 0; + inf.lastfloorportalheight = inf.lastceilingportalheight = start.Z; memset(&res, 0, sizeof(res)); if (inf.TraceTraverse (ptflags)) @@ -196,6 +199,7 @@ void FTraceInfo::EnterSectorPortal(int position, double frac, sector_t *entersec newtrace.aimdir = position; newtrace.limitz = portal->specialf1; newtrace.sectorsel = 0; + newtrace.lastfloorportalheight = newtrace.lastceilingportalheight = limitz; if (newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES)) { @@ -227,7 +231,7 @@ int FTraceInfo::EnterLinePortal(line_t *li, double frac) frac += 1 / MaxDist; double enterdist = MaxDist / frac; - DVector2 enter = newtrace.Start.XY() + enterdist * Vec.XY(); + DVector2 enter = newtrace.Start + enterdist * Vec; newtrace.ActorMask = ActorMask; newtrace.WallMask = WallMask; @@ -244,7 +248,9 @@ int FTraceInfo::EnterLinePortal(line_t *li, double frac) 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; return newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES); @@ -442,11 +448,24 @@ bool FTraceInfo::LineCheck(intercept_t *in) Results->HitType = TRACE_HitFloor; Results->HitTexture = CurSector->GetTexture(sector_t::floor); } - else if (entersector == NULL || entersector->PortalBlocksMovement(sector_t::floor)) + else { - // 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; + if ((TraceFlags & TRACE_ReportPortals) && lastfloorportalheight > fc) + { + lastfloorportalheight = fc; + if (TraceCallback != NULL) + { + // Todo: calculate the intersection point. + Results->HitType = TRACE_CrossingPortal; + 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; + } } } else if (hit.Z >= fc) @@ -457,11 +476,24 @@ bool FTraceInfo::LineCheck(intercept_t *in) Results->HitType = TRACE_HitCeiling; Results->HitTexture = CurSector->GetTexture(sector_t::ceiling); } - else if (entersector == NULL || entersector->PortalBlocksMovement(sector_t::ceiling)) + else { - // 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; + if ((TraceFlags & TRACE_ReportPortals) && lastceilingportalheight < fc) + { + lastceilingportalheight = fc; + if (TraceCallback != NULL) + { + // Todo: calculate the intersection point. + Results->HitType = TRACE_CrossingPortal; + 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()) diff --git a/src/p_trace.h b/src/p_trace.h index 2c817816e..7eaf50ce5 100644 --- a/src/p_trace.h +++ b/src/p_trace.h @@ -50,7 +50,8 @@ enum ETraceResult TRACE_HitFloor, TRACE_HitCeiling, TRACE_HitWall, - TRACE_HitActor + TRACE_HitActor, + TRACE_CrossingPortal, }; enum @@ -113,6 +114,7 @@ enum TRACE_PCross = 2, // Trigger SPAC_PCROSS lines TRACE_Impact = 4, // Trigger SPAC_IMPACT lines TRACE_PortalRestrict= 8, // Cannot go through portals without a static link offset. + TRACE_ReportPortals = 16, // Report any portal crossing to the TraceCallback }; // return values from callback