From 97577dc2d70c2a49a0c8e90eb40c21608a6f1c6e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 5 Mar 2016 21:44:31 +0100 Subject: [PATCH 01/27] - added sector portal support to Trace() Note that at the moment only the function itself has been changed, the calling parts still need to be redone. --- src/p_trace.cpp | 1015 +++++++++++++++++++++++++++++------------------ src/p_trace.h | 2 + 2 files changed, 622 insertions(+), 395 deletions(-) diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 297bf52bc..07f89286d 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -41,6 +41,12 @@ #include "r_defs.h" #include "p_spec.h" +//========================================================================== +// +// +// +//========================================================================== + struct FTraceInfo { fixed_t StartX, StartY, StartZ; @@ -49,6 +55,7 @@ struct FTraceInfo DWORD WallMask; AActor *IgnoreThis; FTraceResults *Results; + FTraceResults *TempResults; sector_t *CurSector; fixed_t MaxDist; fixed_t EnterDist; @@ -57,6 +64,8 @@ struct FTraceInfo DWORD TraceFlags; int inshootthrough; fixed_t startfrac; + int aimdir; + fixed_t limitz; // These are required for 3D-floor checking // to create a fake sector with a floor @@ -64,15 +73,37 @@ struct FTraceInfo sector_t DummySector[2]; int sectorsel; + void Setup3DFloors(); + bool LineCheck(intercept_t *in); + bool ThingCheck(intercept_t *in); bool TraceTraverse (int ptflags); bool CheckPlane(const secplane_t &plane); - bool CheckSectorPlane (const sector_t *sector, bool checkFloor); - bool Check3DFloorPlane(const F3DFloor *ffloor, bool checkBottom); + void EnterLinePortal(line_t *li, fixed_t frac); + void EnterSectorPortal(int position, fixed_t frac, sector_t *entersec); + + + bool CheckSectorPlane(const sector_t *sector, bool checkFloor) + { + return CheckPlane(checkFloor ? sector->floorplane : sector->ceilingplane); + } + + bool FTraceInfo::Check3DFloorPlane(const F3DFloor *ffloor, bool checkBottom) + { + return CheckPlane(checkBottom? *(ffloor->bottom.plane) : *(ffloor->top.plane)); + } + + }; static bool EditTraceResult (DWORD flags, FTraceResults &res); +//========================================================================== +// +// Trace entry point +// +//========================================================================== + bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, fixed_t vx, fixed_t vy, fixed_t vz, fixed_t maxDist, ActorFlags actorMask, DWORD wallMask, AActor *ignore, @@ -81,6 +112,10 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, { int ptflags; FTraceInfo inf; + FTraceResults tempResult; + + memset(&tempResult, 0, sizeof(tempResult)); + tempResult.Fraction = tempResult.Distance = FIXED_MAX; ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS|PT_COMPATIBLE : PT_ADDLINES; @@ -100,8 +135,11 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, inf.TraceCallbackData = callbackdata; inf.TraceFlags = flags; inf.Results = &res; + inf.TempResults = &tempResult; inf.inshootthrough = true; inf.sectorsel=0; + inf.aimdir = -1; + inf.startfrac = 0; memset(&res, 0, sizeof(res)); /* // Redundant with the memset res.HitType = TRACE_HitNone; @@ -133,34 +171,11 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, maxDist = inf.MaxDist = FixedDiv(FIXED_MIN - y, vy); } - // recalculate the trace's end points for robustness if (inf.TraceTraverse (ptflags)) - { // check for intersection with floor/ceiling - res.Sector = §ors[inf.CurSector->sectornum]; - - if (inf.CheckSectorPlane (inf.CurSector, true)) - { - res.HitType = TRACE_HitFloor; - res.HitTexture = inf.CurSector->GetTexture(sector_t::floor); - if (res.CrossedWater == NULL && - inf.CurSector->heightsec != NULL && - inf.CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z) - { - res.CrossedWater = §ors[inf.CurSector->sectornum]; - } - } - else if (inf.CheckSectorPlane (inf.CurSector, false)) - { - res.HitType = TRACE_HitCeiling; - res.HitTexture = inf.CurSector->GetTexture(sector_t::ceiling); - } - } - - if (res.HitType != TRACE_HitNone) - { + { if (flags) { - return EditTraceResult (flags, res); + return EditTraceResult(flags, res); } else { @@ -179,9 +194,116 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, } } -bool FTraceInfo::TraceTraverse (int ptflags) + +//============================================================================ +// +// traverses a sector portal +// +//============================================================================ + +void FTraceInfo::EnterSectorPortal(int position, fixed_t frac, sector_t *entersec) +{ + if (aimdir != -1 && aimdir != position) return; + AActor *portal = entersec->SkyBoxes[position]; + + if (aimdir == sector_t::ceiling && portal->threshold < limitz) return; + else if (aimdir == sector_t::floor && portal->threshold > limitz) return; + + FTraceInfo newtrace; + FTraceResults results; + + memset(&results, 0, sizeof(results)); + + newtrace.StartX = StartX + portal->scaleX; + newtrace.StartY = StartY + portal->scaleY; + newtrace.StartZ = StartZ; + + frac += FixedDiv(FRACUNIT, MaxDist); + fixed_t enterdist = FixedMul(MaxDist, frac); + fixed_t enterX = newtrace.StartX + FixedMul(enterdist, Vx); + fixed_t enterY = newtrace.StartY + FixedMul(enterdist, Vy); + + newtrace.Vx = Vx; + newtrace.Vy = Vy; + newtrace.Vz = Vz; + newtrace.ActorMask = ActorMask; + newtrace.WallMask = WallMask; + newtrace.IgnoreThis = IgnoreThis; + newtrace.Results = &results; + newtrace.TempResults = TempResults; + newtrace.CurSector = P_PointInSector(enterX ,enterY); + 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->threshold; + newtrace.sectorsel = 0; + + if (newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES)) + { + if (newtrace.Results->HitType != TRACE_HitNone) + { + if (newtrace.Results->Fraction < TempResults->Fraction) + { + *TempResults = *newtrace.Results; + } + } + } +} + +//============================================================================ +// +// traverses a line portal +// simply calling PortalRelocate does not work here because more needs to be set up +// +//============================================================================ + +void FTraceInfo::EnterLinePortal(line_t *li, fixed_t frac) +{ + /* + aim_t newtrace = Clone(); + + FLinePortal *port = li->getPortal(); + if (port->mType != PORTT_LINKED && (flags & ALF_PORTALRESTRICT)) return; + + newtrace.toppitch = toppitch; + newtrace.bottompitch = bottompitch; + newtrace.aimdir = aimdir; + newtrace.unlinked = (port->mType != PORTT_LINKED); + newtrace.startpos = startpos; + newtrace.aimtrace = aimtrace; + P_TranslatePortalXY(li, newtrace.startpos.x, newtrace.startpos.y); + P_TranslatePortalZ(li, newtrace.startpos.z); + P_TranslatePortalVXVY(li, newtrace.aimtrace.x, newtrace.aimtrace.y); + + newtrace.startfrac = frac + FixedDiv(FRACUNIT, attackrange); // this is to skip the transition line to the portal which would produce a bogus opening + + fixed_t x = newtrace.startpos.x + FixedMul(newtrace.aimtrace.x, newtrace.startfrac); + fixed_t y = newtrace.startpos.y + FixedMul(newtrace.aimtrace.y, newtrace.startfrac); + + newtrace.lastsector = P_PointInSector(x, y); + P_TranslatePortalZ(li, limitz); + if (aimdebug) + Printf("-----Entering line portal from sector %d to sector %d\n", lastsector->sectornum, newtrace.lastsector->sectornum); + newtrace.AimTraverse(); + SetResult(linetarget, newtrace.linetarget); + SetResult(thing_friend, newtrace.thing_friend); + SetResult(thing_other, newtrace.thing_other); + */ +} + +//========================================================================== +// +// Checks 3D floors at trace start and sets up related data +// +//========================================================================== + +void FTraceInfo::Setup3DFloors() { - // Do a 3D floor check in the starting sector TDeletingArray &ff = CurSector->e->XFloor.ffloors; if (ff.Size()) @@ -195,6 +317,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) fixed_t y = StartY + FixedMul(Vy, sdist); fixed_t z = StartZ + FixedMul(Vz, sdist); + fixed_t bf = CurSector->floorplane.ZatPoint(x, y); fixed_t bc = CurSector->ceilingplane.ZatPoint(x, y); @@ -206,7 +329,10 @@ bool FTraceInfo::TraceTraverse (int ptflags) if (rover->flags&FF_SWIMMABLE && Results->Crossed3DWater == NULL) { if (Check3DFloorPlane(rover, false)) + { Results->Crossed3DWater = rover; + Results->Crossed3DWaterPos = { Results->X, Results->Y, Results->Z }; + } } if (!(rover->flags&FF_SHOOTTHROUGH)) @@ -214,10 +340,10 @@ bool FTraceInfo::TraceTraverse (int ptflags) fixed_t ff_bottom = rover->bottom.plane->ZatPoint(x, y); fixed_t ff_top = rover->top.plane->ZatPoint(x, y); // clip to the part of the sector we are in - if (z>ff_top) + if (z > ff_top) { // above - if (bffloorplane = *rover->top.plane; CurSector->SetTexture(sector_t::floor, *rover->top.texture, false); @@ -225,10 +351,10 @@ bool FTraceInfo::TraceTraverse (int ptflags) bf = ff_top; } } - else if (zff_bottom) + if (bc > ff_bottom) { CurSector->ceilingplane = *rover->bottom.plane; CurSector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false); @@ -239,7 +365,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) else { // inside - if (bffloorplane = *rover->bottom.plane; CurSector->SetTexture(sector_t::floor, *rover->bottom.texture, false); @@ -247,7 +373,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) bf = ff_bottom; } - if (bc>ff_top) + if (bc > ff_top) { CurSector->ceilingplane = *rover->top.plane; CurSector->SetTexture(sector_t::ceiling, *rover->top.texture, false); @@ -259,379 +385,381 @@ bool FTraceInfo::TraceTraverse (int ptflags) } } } - - - FPathTraverse it(StartX, StartY, FixedMul (Vx, MaxDist), FixedMul (Vy, MaxDist), ptflags | PT_DELTA); - intercept_t *in; - - while ((in = it.Next())) + if (!CurSector->PortalBlocksMovement(sector_t::ceiling)) { - fixed_t hitx, hity, hitz; - fixed_t dist; + EnterSectorPortal(sector_t::ceiling, startfrac, CurSector); + } + if (!CurSector->PortalBlocksMovement(sector_t::floor)) + { + EnterSectorPortal(sector_t::floor, startfrac, CurSector); + } +} - // Deal with splashes in 3D floors - if (CurSector->e->XFloor.ffloors.Size()) + +//========================================================================== +// +// Processes one line intercept +// +//========================================================================== + +bool FTraceInfo::LineCheck(intercept_t *in) +{ + int lineside; + sector_t *entersector; + + fixed_t dist = FixedMul(MaxDist, in->frac); + fixed_t hitx = StartX + FixedMul(Vx, dist); + fixed_t hity = StartY + FixedMul(Vy, dist); + fixed_t hitz = StartZ + FixedMul(Vz, dist); + + fixed_t ff, fc, bf = 0, bc = 0; + + if (in->d.line->frontsector->sectornum == CurSector->sectornum) + { + lineside = 0; + } + else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum) + { + lineside = 1; + } + else + { // Dammit. Why does Doom have to allow non-closed sectors? + if (in->d.line->backsector == NULL) { - for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) - { - F3DFloor * rover=CurSector->e->XFloor.ffloors[i]; - if (!(rover->flags&FF_EXISTS)) - continue; - - // Deal with splashy stuff - if (rover->flags&FF_SWIMMABLE && Results->Crossed3DWater == NULL) - { - if (Check3DFloorPlane(rover, false)) - Results->Crossed3DWater = rover; - } - } + lineside = 0; + CurSector = in->d.line->frontsector; } - - if (in->isaline) + else { - int lineside; - sector_t *entersector; + lineside = P_PointOnLineSide(StartX, StartY, in->d.line); + CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector; + } + } - dist = FixedMul (MaxDist, in->frac); - hitx = StartX + FixedMul (Vx, dist); - hity = StartY + FixedMul (Vy, dist); - hitz = StartZ + FixedMul (Vz, dist); + if (!(in->d.line->flags & ML_TWOSIDED)) + { + entersector = NULL; + } + else + { + entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector; - fixed_t ff, fc, bf = 0, bc = 0; - - // CurSector may be a copy so we must compare the sector number, not the index! - if (in->d.line->frontsector->sectornum == CurSector->sectornum) + // For backwards compatibility: Ignore lines with the same sector on both sides. + // This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15) need it. + if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector) + { + // We must check special activation here because the code below is never reached. + if (TraceFlags & TRACE_PCross) { - lineside = 0; + P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_PCross); } - else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum) + if (TraceFlags & TRACE_Impact) { - lineside = 1; + P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact); } - else - { // Dammit. Why does Doom have to allow non-closed sectors? - if (in->d.line->backsector == NULL) + return true; + } + } + + ff = CurSector->floorplane.ZatPoint(hitx, hity); + fc = CurSector->ceilingplane.ZatPoint(hitx, hity); + + if (entersector != NULL) + { + bf = entersector->floorplane.ZatPoint(hitx, hity); + bc = entersector->ceilingplane.ZatPoint(hitx, hity); + } + + sector_t *hsec = CurSector->GetHeightSec(); + if (Results->CrossedWater == NULL && + hsec != NULL && + //CurSector->heightsec->waterzone && + hitz <= hsec->floorplane.ZatPoint(hitx, hity)) + { + // hit crossed a water plane + if (CheckSectorPlane(hsec, true)) + { + Results->CrossedWater = §ors[CurSector->sectornum]; + Results->CrossedWaterPos = { Results->X, Results->Y, Results->Z }; + } + } + + if (hitz <= 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 (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 (hitz >= 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 (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 (entersector == NULL || + hitz < bf || hitz > bc || + in->d.line->flags & WallMask) + { + // hit the wall + Results->HitType = TRACE_HitWall; + Results->Tier = + entersector == NULL ? TIER_Middle : + hitz <= bf ? TIER_Lower : + hitz >= bc ? TIER_Upper : TIER_Middle; + if (TraceFlags & TRACE_Impact) + { + P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact); + } + } + else + { // made it past the wall + // check for 3D floors first + if (entersector->e->XFloor.ffloors.Size()) + { + memcpy(&DummySector[sectorsel], entersector, sizeof(sector_t)); + entersector = &DummySector[sectorsel]; + sectorsel ^= 1; + + for (auto rover : entersector->e->XFloor.ffloors) + { + int entershootthrough = !!(rover->flags&FF_SHOOTTHROUGH); + + if (entershootthrough != inshootthrough && rover->flags&FF_EXISTS) { - lineside = 0; - CurSector = in->d.line->frontsector; - } - else - { - lineside = P_PointOnLineSide (StartX, StartY, in->d.line); - CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector; - } - } + fixed_t ff_bottom = rover->bottom.plane->ZatPoint(hitx, hity); + fixed_t ff_top = rover->top.plane->ZatPoint(hitx, hity); - if (!(in->d.line->flags & ML_TWOSIDED)) - { - entersector = NULL; - } - else - { - entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector; - - // For backwards compatibility: Ignore lines with the same sector on both sides. - // This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15) need it. - if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector) - { - // We must check special activation here because the code below is never reached. - if (TraceFlags & TRACE_PCross) + // clip to the part of the sector we are in + if (hitz > ff_top) { - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCross); - } - if (TraceFlags & TRACE_Impact) - { - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact); - } - continue; - } - } - - ff = CurSector->floorplane.ZatPoint (hitx, hity); - fc = CurSector->ceilingplane.ZatPoint (hitx, hity); - - if (entersector != NULL) - { - bf = entersector->floorplane.ZatPoint (hitx, hity); - bc = entersector->ceilingplane.ZatPoint (hitx, hity); - } - - sector_t *hsec = CurSector->GetHeightSec(); - if (Results->CrossedWater == NULL && - hsec != NULL && - //CurSector->heightsec->waterzone && - hitz <= hsec->floorplane.ZatPoint (hitx, hity)) - { - // hit crossed a water plane - Results->CrossedWater = §ors[CurSector->sectornum]; - } - - if (hitz <= ff) - { // hit floor in front of wall - Results->HitType = TRACE_HitFloor; - Results->HitTexture = CurSector->GetTexture(sector_t::floor); - } - else if (hitz >= fc) - { // hit ceiling in front of wall - Results->HitType = TRACE_HitCeiling; - Results->HitTexture = CurSector->GetTexture(sector_t::ceiling); - } - else if (entersector == NULL || - hitz < bf || hitz > bc || - in->d.line->flags & WallMask) - { // hit the wall - Results->HitType = TRACE_HitWall; - Results->Tier = - entersector == NULL ? TIER_Middle : - hitz <= bf ? TIER_Lower : - hitz >= bc ? TIER_Upper : TIER_Middle; - if (TraceFlags & TRACE_Impact) - { - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact); - } - } - else - { // made it past the wall - // check for 3D floors first - if (entersector->e->XFloor.ffloors.Size()) - { - memcpy(&DummySector[sectorsel],entersector,sizeof(sector_t)); - entersector=&DummySector[sectorsel]; - sectorsel^=1; - - for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) - { - F3DFloor * rover=entersector->e->XFloor.ffloors[i]; - int entershootthrough = !!(rover->flags&FF_SHOOTTHROUGH); - - if (entershootthrough != inshootthrough && rover->flags&FF_EXISTS) + // above + if (bf < ff_top) { - fixed_t ff_bottom=rover->bottom.plane->ZatPoint(hitx, hity); - fixed_t ff_top=rover->top.plane->ZatPoint(hitx, hity); - - // clip to the part of the sector we are in - if (hitz>ff_top) - { - // above - if (bffloorplane=*rover->top.plane; - entersector->SetTexture(sector_t::floor, *rover->top.texture, false); - bf=ff_top; - } - } - else if (hitzff_bottom) - { - entersector->ceilingplane=*rover->bottom.plane; - entersector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false); - bc=ff_bottom; - } - } - else - { - //hit the edge - equivalent to hitting the wall - Results->HitType = TRACE_HitWall; - Results->Tier = TIER_FFloor; - Results->ffloor = rover; - if ((TraceFlags & TRACE_Impact) && in->d.line->special) - { - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact); - } - goto cont; - } + entersector->floorplane = *rover->top.plane; + entersector->SetTexture(sector_t::floor, *rover->top.texture, false); + entersector->SkyBoxes[sector_t::floor] = NULL; + bf = ff_top; } } - } - - Results->HitType = TRACE_HitNone; - if (TraceFlags & TRACE_PCross) - { - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCross); - } - if (TraceFlags & TRACE_Impact) - { // This is incorrect for "impact", but Hexen did this, so - // we need to as well, for compatibility - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact); - } - } -cont: - - if (Results->HitType != TRACE_HitNone) - { - // We hit something, so figure out where exactly - Results->Sector = §ors[CurSector->sectornum]; - - if (Results->HitType != TRACE_HitWall && - !CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor)) - { // trace is parallel to the plane (or right on it) - if (entersector == NULL) + else if (hitz < ff_bottom) { - Results->HitType = TRACE_HitWall; - Results->Tier = TIER_Middle; + //below + if (bc > ff_bottom) + { + entersector->ceilingplane = *rover->bottom.plane; + entersector->SetTexture(sector_t::ceiling, *rover->bottom.texture, false); + entersector->SkyBoxes[sector_t::ceiling] = NULL; + bc = ff_bottom; + } } else { - if (hitz <= bf || hitz >= bc) + //hit the edge - equivalent to hitting the wall + Results->HitType = TRACE_HitWall; + Results->Tier = TIER_FFloor; + Results->ffloor = rover; + if ((TraceFlags & TRACE_Impact) && in->d.line->special) { - Results->HitType = TRACE_HitWall; - Results->Tier = - hitz <= bf ? TIER_Lower : - hitz >= bc ? TIER_Upper : TIER_Middle; + P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact); } - else - { - Results->HitType = TRACE_HitNone; - } - } - if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact) - { - P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_Impact); + goto cont; } } - - if (Results->HitType == TRACE_HitWall) - { - Results->X = hitx; - Results->Y = hity; - Results->Z = hitz; - Results->Distance = dist; - Results->Fraction = in->frac; - Results->Line = in->d.line; - Results->Side = lineside; - } } + } - if (Results->HitType == TRACE_HitNone) - { - CurSector = entersector; - EnterDist = dist; - continue; - } + Results->HitType = TRACE_HitNone; + if (TraceFlags & TRACE_PCross) + { + P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_PCross); + } + if (TraceFlags & TRACE_Impact) + { // This is incorrect for "impact", but Hexen did this, so + // we need to as well, for compatibility + P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact); + } - if (TraceCallback != NULL) + 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: + + if (Results->HitType != TRACE_HitNone) + { + // We hit something, so figure out where exactly + Results->Sector = §ors[CurSector->sectornum]; + + if (Results->HitType != TRACE_HitWall && + !CheckSectorPlane(CurSector, Results->HitType == TRACE_HitFloor)) + { // trace is parallel to the plane (or right on it) + if (entersector == NULL) { - switch (TraceCallback(*Results, TraceCallbackData)) - { - case TRACE_Stop: return false; - case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; - case TRACE_Skip: Results->HitType = TRACE_HitNone; break; - default: break; - } + Results->HitType = TRACE_HitWall; + Results->Tier = TIER_Middle; } else { - return false; - } - } - - // Encountered an actor - if (!(in->d.thing->flags & ActorMask) || in->d.thing == IgnoreThis) - { - continue; - } - - dist = FixedMul (MaxDist, in->frac); - hitx = StartX + FixedMul (Vx, dist); - hity = StartY + FixedMul (Vy, dist); - hitz = StartZ + FixedMul (Vz, dist); - - if (hitz > in->d.thing->Top()) - { // trace enters above actor - if (Vz >= 0) continue; // Going up: can't hit - - // Does it hit the top of the actor? - dist = FixedDiv(in->d.thing->Top() - StartZ, Vz); - - if (dist > MaxDist) continue; - in->frac = FixedDiv(dist, MaxDist); - - hitx = StartX + FixedMul (Vx, dist); - hity = StartY + FixedMul (Vy, dist); - hitz = StartZ + FixedMul (Vz, dist); - - // calculated coordinate is outside the actor's bounding box - if (abs(hitx - in->d.thing->X()) > in->d.thing->radius || - abs(hity - in->d.thing->Y()) > in->d.thing->radius) continue; - } - else if (hitz < in->d.thing->Z()) - { // trace enters below actor - if (Vz <= 0) continue; // Going down: can't hit - - // Does it hit the bottom of the actor? - dist = FixedDiv(in->d.thing->Z() - StartZ, Vz); - if (dist > MaxDist) continue; - in->frac = FixedDiv(dist, MaxDist); - - hitx = StartX + FixedMul (Vx, dist); - hity = StartY + FixedMul (Vy, dist); - hitz = StartZ + FixedMul (Vz, dist); - - // calculated coordinate is outside the actor's bounding box - if (abs(hitx - in->d.thing->X()) > in->d.thing->radius || - abs(hity - in->d.thing->Y()) > in->d.thing->radius) continue; - } - - // check for extrafloors first - if (CurSector->e->XFloor.ffloors.Size()) - { - fixed_t ff_floor=CurSector->floorplane.ZatPoint(hitx, hity); - fixed_t ff_ceiling=CurSector->ceilingplane.ZatPoint(hitx, hity); - - if (hitz>ff_ceiling) // actor is hit above the current ceiling - { - Results->HitType=TRACE_HitCeiling; - Results->HitTexture = CurSector->GetTexture(sector_t::ceiling); - } - else if (hitzHitType=TRACE_HitFloor; - Results->HitTexture = CurSector->GetTexture(sector_t::floor); - } - else goto cont1; - - // the trace hit a 3D-floor before the thing. - // Calculate an intersection and abort. - Results->Sector = §ors[CurSector->sectornum]; - if (!CheckSectorPlane(CurSector, Results->HitType == TRACE_HitFloor)) - { - Results->HitType = TRACE_HitNone; - } - if (TraceCallback != NULL) - { - switch (TraceCallback(*Results, TraceCallbackData)) + if (hitz <= bf || hitz >= bc) { - case TRACE_Continue: return true; - case TRACE_Stop: return false; - case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; - case TRACE_Skip: Results->HitType = TRACE_HitNone; return true; + Results->HitType = TRACE_HitWall; + Results->Tier = + hitz <= bf ? TIER_Lower : + hitz >= bc ? TIER_Upper : TIER_Middle; + } + else + { + Results->HitType = TRACE_HitNone; } } - else + if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact) { - return false; + P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_Impact); } } -cont1: - Results->HitType = TRACE_HitActor; - Results->X = hitx; - Results->Y = hity; - Results->Z = hitz; - Results->Distance = dist; - Results->Fraction = in->frac; - Results->Actor = in->d.thing; + if (Results->HitType == TRACE_HitWall) + { + Results->X = hitx; + Results->Y = hity; + Results->Z = hitz; + Results->Distance = dist; + Results->Fraction = in->frac; + Results->Line = in->d.line; + Results->Side = lineside; + } + } + if (TraceCallback != NULL && Results->HitType != TRACE_HitNone) + { + switch (TraceCallback(*Results, TraceCallbackData)) + { + case TRACE_Stop: return false; + case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; + case TRACE_Skip: Results->HitType = TRACE_HitNone; break; + default: break; + } + } + + if (Results->HitType == TRACE_HitNone) + { + CurSector = entersector; + EnterDist = dist; + return true; + } + else + { + return false; + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +bool FTraceInfo::ThingCheck(intercept_t *in) +{ + fixed_t dist = FixedMul(MaxDist, in->frac); + fixed_t hitx = StartX + FixedMul(Vx, dist); + fixed_t hity = StartY + FixedMul(Vy, dist); + fixed_t hitz = StartZ + FixedMul(Vz, dist); + + if (hitz > in->d.thing->Top()) + { + // trace enters above actor + if (Vz >= 0) return true; // Going up: can't hit + + // Does it hit the top of the actor? + dist = FixedDiv(in->d.thing->Top() - StartZ, Vz); + + if (dist > MaxDist) return true; + in->frac = FixedDiv(dist, MaxDist); + + hitx = StartX + FixedMul(Vx, dist); + hity = StartY + FixedMul(Vy, dist); + hitz = StartZ + FixedMul(Vz, dist); + + // calculated coordinate is outside the actor's bounding box + if (abs(hitx - in->d.thing->X()) > in->d.thing->radius || + abs(hity - in->d.thing->Y()) > in->d.thing->radius) return true; + } + else if (hitz < in->d.thing->Z()) + { // trace enters below actor + if (Vz <= 0) return true; // Going down: can't hit + + // Does it hit the bottom of the actor? + dist = FixedDiv(in->d.thing->Z() - StartZ, Vz); + if (dist > MaxDist) return true; + in->frac = FixedDiv(dist, MaxDist); + + hitx = StartX + FixedMul(Vx, dist); + hity = StartY + FixedMul(Vy, dist); + hitz = StartZ + FixedMul(Vz, dist); + + // calculated coordinate is outside the actor's bounding box + if (abs(hitx - in->d.thing->X()) > in->d.thing->radius || + abs(hity - in->d.thing->Y()) > in->d.thing->radius) return true; + } + + if (CurSector->e->XFloor.ffloors.Size()) + { + // check for 3D floor hits first. + fixed_t ff_floor = CurSector->floorplane.ZatPoint(hitx, hity); + fixed_t ff_ceiling = CurSector->ceilingplane.ZatPoint(hitx, hity); + + if (hitz > ff_ceiling && CurSector->PortalBlocksMovement(sector_t::ceiling)) // actor is hit above the current ceiling + { + Results->HitType = TRACE_HitCeiling; + Results->HitTexture = CurSector->GetTexture(sector_t::ceiling); + } + else if (hitz < ff_floor && CurSector->PortalBlocksMovement(sector_t::floor)) // actor is hit below the current floor + { + Results->HitType = TRACE_HitFloor; + Results->HitTexture = CurSector->GetTexture(sector_t::floor); + } + else goto cont1; + + // the trace hit a 3D floor before the thing. + // Calculate an intersection and abort. + Results->Sector = §ors[CurSector->sectornum]; + if (!CheckSectorPlane(CurSector, Results->HitType == TRACE_HitFloor)) + { + Results->HitType = TRACE_HitNone; + } if (TraceCallback != NULL) { switch (TraceCallback(*Results, TraceCallbackData)) { - case TRACE_Stop: return false; - case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; - case TRACE_Skip: Results->HitType = TRACE_HitNone; break; - default: break; + case TRACE_Continue: return true; + case TRACE_Stop: return false; + case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; + case TRACE_Skip: Results->HitType = TRACE_HitNone; return true; } } else @@ -639,9 +767,132 @@ cont1: return false; } } +cont1: + + + Results->HitType = TRACE_HitActor; + Results->X = hitx; + Results->Y = hity; + Results->Z = hitz; + Results->Distance = dist; + Results->Fraction = in->frac; + Results->Actor = in->d.thing; + + if (TraceCallback != NULL) + { + switch (TraceCallback(*Results, TraceCallbackData)) + { + case TRACE_Stop: return false; + case TRACE_Abort: Results->HitType = TRACE_HitNone; return false; + case TRACE_Skip: Results->HitType = TRACE_HitNone; return true; + default: return true; + } + } + else + { + return false; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FTraceInfo::TraceTraverse (int ptflags) +{ + // Do a 3D floor check in the starting sector + Setup3DFloors(); + + FPathTraverse it(StartX, StartY, FixedMul (Vx, MaxDist), FixedMul (Vy, MaxDist), ptflags | PT_DELTA, startfrac); + intercept_t *in; + int lastsplashsector = -1; + + while ((in = it.Next())) + { + // Deal with splashes in 3D floors (but only run once per sector, not each iteration - and stop if something was found.) + if (Results->Crossed3DWater == NULL && lastsplashsector != CurSector->sectornum) + { + for (auto rover : CurSector->e->XFloor.ffloors) + { + if ((rover->flags & FF_EXISTS) && (rover->flags&FF_SWIMMABLE)) + { + if (Check3DFloorPlane(rover, false)) + { + Results->Crossed3DWater = rover; + Results->Crossed3DWaterPos = { Results->X, Results->Y, Results->Z }; + } + } + } + lastsplashsector = CurSector->sectornum; + } + + // We have something closer in the storage for portal subtraces. + if (TempResults->HitType != TRACE_HitNone && in->frac > TempResults->Fraction) + { + break; + } + else if (in->isaline) + { + if (!LineCheck(in)) break; + } + else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis) + { + if (!ThingCheck(in)) 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)) + { + *Results = *TempResults; + return true; + } + else if (Results->HitType == TRACE_HitNone) + { + if (CurSector->PortalBlocksMovement(sector_t::floor) && CheckSectorPlane(CurSector, true)) + { + Results->HitType = TRACE_HitFloor; + Results->HitTexture = CurSector->GetTexture(sector_t::floor); + } + else if (CurSector->PortalBlocksMovement(sector_t::ceiling) && CheckSectorPlane(CurSector, false)) + { + Results->HitType = TRACE_HitCeiling; + Results->HitTexture = CurSector->GetTexture(sector_t::ceiling); + } + } + + // check for intersection with floor/ceiling + Results->Sector = §ors[CurSector->sectornum]; + + if (Results->CrossedWater == NULL && + CurSector->heightsec != NULL && + CurSector->heightsec->floorplane.ZatPoint(Results->X, Results->Y) >= Results->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->X, Results->Y, Results->Z }; + } + Results = res; + } + return true; } +//========================================================================== +// +// +// +//========================================================================== + bool FTraceInfo::CheckPlane (const secplane_t &plane) { fixed_t den = TMulScale16 (plane.a, Vx, plane.b, Vy, plane.c, Vz); @@ -667,37 +918,11 @@ bool FTraceInfo::CheckPlane (const secplane_t &plane) return false; } -bool FTraceInfo::CheckSectorPlane (const sector_t *sector, bool checkFloor) -{ - secplane_t plane; - - if (checkFloor) - { - plane = sector->floorplane; - } - else - { - plane = sector->ceilingplane; - } - - return CheckPlane(plane); -} - -bool FTraceInfo::Check3DFloorPlane (const F3DFloor *ffloor, bool checkBottom) -{ - secplane_t plane; - - if (checkBottom) - { - plane = *(ffloor->bottom.plane); - } - else - { - plane = *(ffloor->top.plane); - } - - return CheckPlane(plane); -} +//========================================================================== +// +// +// +//========================================================================== static bool EditTraceResult (DWORD flags, FTraceResults &res) { diff --git a/src/p_trace.h b/src/p_trace.h index 1b0815833..16f440037 100644 --- a/src/p_trace.h +++ b/src/p_trace.h @@ -78,7 +78,9 @@ struct FTraceResults BYTE Tier; ETraceResult HitType; sector_t *CrossedWater; // For Boom-style, Transfer_Heights-based deep water + fixedvec3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash F3DFloor *Crossed3DWater; // For 3D floor-based deep water + fixedvec3 Crossed3DWaterPos; F3DFloor *ffloor; }; From 983e8bc6a5714f0d317d2458f8346c6d6c01a98c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 5 Mar 2016 22:39:53 +0100 Subject: [PATCH 02/27] - explicitly check NAME_Null in P_FindTerrain so that it cannot get rendered inoperable by mods which hijack this name. This name must be reserved so that there is some means to disable a sector's terrain. --- src/p_terrain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index 37c2bda0e..3c6519393 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -702,6 +702,7 @@ int P_FindTerrain (FName name) { unsigned int i; + if (name == NAME_Null) return -1; for (i = 0; i < Terrains.Size (); i++) { if (Terrains[i].Name == name) From ae4cc9669bdd84844bca943066dd2c66b5f1bb75 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Mar 2016 01:04:19 +0100 Subject: [PATCH 03/27] - added line portal support to Trace(). --- src/p_trace.cpp | 84 ++++++++++++++++++++++++++++++++----------------- src/p_trace.h | 1 + 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 07f89286d..1a983987d 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -78,7 +78,7 @@ struct FTraceInfo bool ThingCheck(intercept_t *in); bool TraceTraverse (int ptflags); bool CheckPlane(const secplane_t &plane); - void EnterLinePortal(line_t *li, fixed_t frac); + int EnterLinePortal(line_t *li, fixed_t frac); void EnterSectorPortal(int position, fixed_t frac, sector_t *entersec); @@ -262,38 +262,50 @@ void FTraceInfo::EnterSectorPortal(int position, fixed_t frac, sector_t *enterse // //============================================================================ -void FTraceInfo::EnterLinePortal(line_t *li, fixed_t frac) +int FTraceInfo::EnterLinePortal(line_t *li, fixed_t frac) { - /* - aim_t newtrace = Clone(); - FLinePortal *port = li->getPortal(); - if (port->mType != PORTT_LINKED && (flags & ALF_PORTALRESTRICT)) return; - newtrace.toppitch = toppitch; - newtrace.bottompitch = bottompitch; + // The caller cannot handle portals without global offset. + if (port->mType != PORTT_LINKED && (TraceFlags & TRACE_PortalRestrict)) return -1; + + FTraceInfo newtrace; + + newtrace.StartX = StartX; + newtrace.StartY = StartY; + newtrace.StartZ = StartZ; + newtrace.Vx = Vx; + newtrace.Vy = Vy; + newtrace.Vz = Vz; + + P_TranslatePortalXY(li, newtrace.StartX, newtrace.StartY); + P_TranslatePortalZ(li, newtrace.StartZ); + P_TranslatePortalVXVY(li, newtrace.Vx, newtrace.Vy); + + frac += FixedDiv(FRACUNIT, MaxDist); + fixed_t enterdist = FixedMul(MaxDist, frac); + fixed_t enterX = newtrace.StartX + FixedMul(enterdist, Vx); + fixed_t enterY = newtrace.StartY + FixedMul(enterdist, Vy); + + newtrace.ActorMask = ActorMask; + newtrace.WallMask = WallMask; + newtrace.IgnoreThis = IgnoreThis; + newtrace.Results = Results; + newtrace.TempResults = TempResults; + newtrace.CurSector = P_PointInSector(enterX, enterY); + 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.unlinked = (port->mType != PORTT_LINKED); - newtrace.startpos = startpos; - newtrace.aimtrace = aimtrace; - P_TranslatePortalXY(li, newtrace.startpos.x, newtrace.startpos.y); - P_TranslatePortalZ(li, newtrace.startpos.z); - P_TranslatePortalVXVY(li, newtrace.aimtrace.x, newtrace.aimtrace.y); - - newtrace.startfrac = frac + FixedDiv(FRACUNIT, attackrange); // this is to skip the transition line to the portal which would produce a bogus opening - - fixed_t x = newtrace.startpos.x + FixedMul(newtrace.aimtrace.x, newtrace.startfrac); - fixed_t y = newtrace.startpos.y + FixedMul(newtrace.aimtrace.y, newtrace.startfrac); - - newtrace.lastsector = P_PointInSector(x, y); - P_TranslatePortalZ(li, limitz); - if (aimdebug) - Printf("-----Entering line portal from sector %d to sector %d\n", lastsector->sectornum, newtrace.lastsector->sectornum); - newtrace.AimTraverse(); - SetResult(linetarget, newtrace.linetarget); - SetResult(thing_friend, newtrace.thing_friend); - SetResult(thing_other, newtrace.thing_other); - */ + newtrace.limitz = limitz; + P_TranslatePortalZ(li, newtrace.limitz); + newtrace.sectorsel = 0; + Results->unlinked = true; + return newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES); } //========================================================================== @@ -514,10 +526,24 @@ bool FTraceInfo::LineCheck(intercept_t *in) return false; } } + else if (in->d.line->isLinePortal()) + { + if (entersector == NULL || (hitz >= bf && hitz <= 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. + } else if (entersector == NULL || hitz < bf || hitz > bc || in->d.line->flags & WallMask) { +normalline: // hit the wall Results->HitType = TRACE_HitWall; Results->Tier = diff --git a/src/p_trace.h b/src/p_trace.h index 16f440037..d02498133 100644 --- a/src/p_trace.h +++ b/src/p_trace.h @@ -76,6 +76,7 @@ struct FTraceResults line_t *Line; // valid if hit a line BYTE Side; BYTE Tier; + bool unlinked; // passed through a portal without static offset. ETraceResult HitType; sector_t *CrossedWater; // For Boom-style, Transfer_Heights-based deep water fixedvec3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash From 74592334e436c3d505b498df74f0966f01380065 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Mar 2016 01:41:52 +0100 Subject: [PATCH 04/27] - fixed return conditions of Trace() so that it always returns something valid. Due to the portal related changes the default initialization for TRACE_HitNone must be inside TraceTraverse. --- src/p_trace.cpp | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 1a983987d..d8c5aa781 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -141,22 +141,17 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, inf.aimdir = -1; inf.startfrac = 0; memset(&res, 0, sizeof(res)); - /* // Redundant with the memset - res.HitType = TRACE_HitNone; - res.CrossedWater = NULL; - res.Crossed3DWater = NULL; - */ // check for overflows and clip if necessary SQWORD xd = (SQWORD)x + ((SQWORD(vx) * SQWORD(maxDist)) >> 16); if (xd>SQWORD(32767)*FRACUNIT) { - maxDist = inf.MaxDist = FixedDiv(FIXED_MAX - x, vx); + inf.MaxDist = FixedDiv(FIXED_MAX - x, vx); } else if (xd<-SQWORD(32767)*FRACUNIT) { - maxDist = inf.MaxDist = FixedDiv(FIXED_MIN - x, vx); + inf.MaxDist = FixedDiv(FIXED_MIN - x, vx); } @@ -164,32 +159,19 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, if (yd>SQWORD(32767)*FRACUNIT) { - maxDist = inf.MaxDist = FixedDiv(FIXED_MAX - y, vy); + inf.MaxDist = FixedDiv(FIXED_MAX - y, vy); } else if (yd<-SQWORD(32767)*FRACUNIT) { - maxDist = inf.MaxDist = FixedDiv(FIXED_MIN - y, vy); + inf.MaxDist = FixedDiv(FIXED_MIN - y, vy); } if (inf.TraceTraverse (ptflags)) { - if (flags) - { - return EditTraceResult(flags, res); - } - else - { - return true; - } + return flags ? EditTraceResult(flags, res) : true; } else { - res.HitType = TRACE_HitNone; - res.X = x + FixedMul (vx, maxDist); - res.Y = y + FixedMul (vy, maxDist); - res.Z = z + FixedMul (vz, maxDist); - res.Distance = maxDist; - res.Fraction = FRACUNIT; return false; } } @@ -909,8 +891,15 @@ bool FTraceInfo::TraceTraverse (int ptflags) } Results = res; } - - return true; + if (Results->HitType == TRACE_HitNone && Results->Distance == 0) + { + Results->X = StartX + FixedMul(Vx, MaxDist); + Results->Y = StartY + FixedMul(Vy, MaxDist); + Results->Z = StartZ + FixedMul(Vz, MaxDist); + Results->Distance = MaxDist; + Results->Fraction = FRACUNIT; + } + return Results->HitType != TRACE_HitNone; } //========================================================================== From a0b2915b8fd4c253f156eb2d376ca56637ef4752 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Mar 2016 02:07:04 +0100 Subject: [PATCH 05/27] - added a heightsec change when aborting the main trace due to having found a target in a subtrace. - be a bit smarter about what to copy from a subtrace. There's 3 distinct pieces of information here: The hit itself, the CrossedWater setting for Boom-transfers and the CrossedWater setting for 3D floors. Note: Ideally this should return all water hits it can detect, not just the first one. --- src/p_trace.cpp | 28 ++++++++++++++++++++-------- src/p_trace.h | 25 +++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/p_trace.cpp b/src/p_trace.cpp index d8c5aa781..ad2bb269c 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -227,13 +227,7 @@ void FTraceInfo::EnterSectorPortal(int position, fixed_t frac, sector_t *enterse if (newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES)) { - if (newtrace.Results->HitType != TRACE_HitNone) - { - if (newtrace.Results->Fraction < TempResults->Fraction) - { - *TempResults = *newtrace.Results; - } - } + Results->CopyIfCloser(TempResults); } } @@ -855,7 +849,25 @@ bool FTraceInfo::TraceTraverse (int ptflags) if (TempResults->HitType != TRACE_HitNone && (Results->HitType == TRACE_HitNone || Results->Fraction > TempResults->Fraction)) { - *Results = *TempResults; + // 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->X, Results->Y) >= Results->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->X, Results->Y, Results->Z }; + } + Results = res; + } + + Results->CopyIfCloser(TempResults); return true; } else if (Results->HitType == TRACE_HitNone) diff --git a/src/p_trace.h b/src/p_trace.h index d02498133..641a8c007 100644 --- a/src/p_trace.h +++ b/src/p_trace.h @@ -36,6 +36,7 @@ #include #include "actor.h" +#include "cmdlib.h" #include "textures/textures.h" struct sector_t; @@ -70,7 +71,7 @@ struct FTraceResults fixed_t Distance; fixed_t Fraction; - + AActor *Actor; // valid if hit an actor line_t *Line; // valid if hit a line @@ -78,12 +79,32 @@ struct FTraceResults BYTE Tier; bool unlinked; // passed through a portal without static offset. ETraceResult HitType; + F3DFloor *ffloor; + sector_t *CrossedWater; // For Boom-style, Transfer_Heights-based deep water fixedvec3 CrossedWaterPos; // remember the position so that we can use it for spawning the splash F3DFloor *Crossed3DWater; // For 3D floor-based deep water fixedvec3 Crossed3DWaterPos; - F3DFloor *ffloor; + + 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; + } + } }; + enum { From 90553bb61c07406c75afbab838077cec99624ecd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Mar 2016 13:10:42 +0100 Subject: [PATCH 06/27] - deal with portals in P_AimCamera. This will most likely need some more testing and refining but at least it should work through line portals now. --- src/p_local.h | 2 +- src/p_map.cpp | 3 ++- src/r_utility.cpp | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index 19315dedb..e1c12e652 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -351,7 +351,7 @@ bool P_CheckMissileSpawn (AActor *missile, fixed_t maxdist); void P_PlaySpawnSound(AActor *missile, AActor *spawner); // [RH] Position the chasecam -void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec); +void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec, bool &unlinked); // [RH] Means of death enum diff --git a/src/p_map.cpp b/src/p_map.cpp index 7894e7382..a0ecc58f7 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4874,7 +4874,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i CVAR(Float, chase_height, -8.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, chase_dist, 90.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &CameraZ, sector_t *&CameraSector) +void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &CameraZ, sector_t *&CameraSector, bool &unlinked) { fixed_t distance = (fixed_t)(clamp(chase_dist, 0, 30000) * FRACUNIT); angle_t angle = (t1->angle - ANG180) >> ANGLETOFINESHIFT; @@ -4905,6 +4905,7 @@ void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &Camera CameraZ = trace.Z; } CameraSector = trace.Sector; + unlinked = trace.unlinked; } diff --git a/src/r_utility.cpp b/src/r_utility.cpp index d301b45fc..dbe5fadd6 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -927,6 +927,7 @@ void R_SetupFrame (AActor *actor) player_t *player = actor->player; unsigned int newblend; InterpolationViewer *iview; + bool unlinked = false; if (player != NULL && player->mo == actor) { // [RH] Use camera instead of viewplayer @@ -962,9 +963,22 @@ void R_SetupFrame (AActor *actor) if (player != NULL && gamestate != GS_TITLELEVEL && ((player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0))) { + sector_t *oldsector = R_PointInSubsector(iview->oviewx, iview->oviewy)->sector; // [RH] Use chasecam view - P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector); + P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector, unlinked); r_showviewer = true; + // Interpolating this is a very complicated thing because nothing keeps track of the aim camera's movement, so whenever we detect a portal transition + // it's probably best to just reset the interpolation for this move. + // Note that this can still cause problems with unusually linked portals + if (viewsector->PortalGroup != oldsector->PortalGroup || (unlinked && P_AproxDistance(iview->oviewx - iview->nviewx, iview->oviewy - iview->nviewy) > 256 * FRACUNIT)) + { + iview->otic = nowtic; + iview->oviewx = iview->nviewx; + iview->oviewy = iview->nviewy; + iview->oviewz = iview->nviewz; + iview->oviewpitch = iview->nviewpitch; + iview->oviewangle = iview->nviewangle; + } } else { From 5175d56129422622bd9ca8505288b7d2dd2211df Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 6 Mar 2016 21:58:36 +0100 Subject: [PATCH 07/27] - made adjustments to P_LineAttack and P_RailAttack to deal with altered angles by passing through a non-parallel portal. - fixed: P_FindFloorCeiling set the floorsector for a new ceilingheight. Note: P_DrawRailTrail still needs to be changed, at the moment rail trails through portals will not work correctly. --- src/actor.h | 5 + src/basictypes.h | 42 ++++++-- src/d_net.cpp | 4 +- src/g_doom/a_revenant.cpp | 2 +- src/g_shared/a_decals.cpp | 24 ++--- src/g_shared/a_sharedglobal.h | 4 +- src/p_local.h | 18 +++- src/p_map.cpp | 164 +++++++++++++----------------- src/p_mobj.cpp | 31 +++--- src/p_trace.cpp | 51 ++++++---- src/p_trace.h | 3 +- src/portal.cpp | 5 - src/thingdef/thingdef_codeptr.cpp | 2 +- 13 files changed, 187 insertions(+), 168 deletions(-) diff --git a/src/actor.h b/src/actor.h index 51ce9752c..b5b32611c 100644 --- a/src/actor.h +++ b/src/actor.h @@ -829,6 +829,11 @@ public: return R_PointToAngle2(X(), Y(), otherx, othery); } + fixed_t AngleTo(fixedvec2 other) + { + return R_PointToAngle2(X(), Y(), other.x, other.y); + } + // 'absolute' is reserved for a linked portal implementation which needs // to distinguish between portal-aware and portal-unaware distance calculation. fixed_t AproxDistance(AActor *other, bool absolute = false) diff --git a/src/basictypes.h b/src/basictypes.h index 356e197dd..6c71fce9b 100644 --- a/src/basictypes.h +++ b/src/basictypes.h @@ -112,30 +112,56 @@ struct fixedvec3 return *this; } + fixedvec3 &operator -=(const fixedvec2 &other) + { + x -= other.x; + y -= other.y; + return *this; + } + + fixedvec3 &operator -=(const fixedvec3 &other) + { + x -= other.x; + y -= other.y; + z -= other.z; + return *this; + } + operator fixedvec2() { - fixedvec2 ret = { x, y }; - return ret; + return { x, y }; } }; inline fixedvec2 operator +(const fixedvec2 &v1, const fixedvec2 &v2) { - fixedvec2 v = { v1.x + v2.x, v1.y + v2.y }; - return v; + return { v1.x + v2.x, v1.y + v2.y }; +} + +inline fixedvec2 operator -(const fixedvec2 &v1, const fixedvec2 &v2) +{ + return { v1.x - v2.x, v1.y - v2.y }; } inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec3 &v2) { - fixedvec3 v = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; - return v; + return { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; } inline fixedvec3 operator +(const fixedvec3 &v1, const fixedvec2 &v2) { - fixedvec3 v = { v1.x + v2.x, v1.y + v2.y, v1.z }; - return v; + return { v1.x + v2.x, v1.y + v2.y, v1.z }; +} + +inline fixedvec3 operator -(const fixedvec3 &v1, const fixedvec2 &v2) +{ + return{ v1.x - v2.x, v1.y - v2.y, v1.z }; +} + +inline fixedvec3 operator -(const fixedvec3 &v1, const fixedvec3 &v2) +{ + return{ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; } #define FIXED_MAX (signed)(0x7fffffff) diff --git a/src/d_net.cpp b/src/d_net.cpp index faba5ef41..4d8e33d3d 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2382,9 +2382,7 @@ void Net_DoCommand (int type, BYTE **stream, int player) { if (trace.HitType == TRACE_HitWall) { - DImpactDecal::StaticCreate (s, - trace.X, trace.Y, trace.Z, - trace.Line->sidedef[trace.Side], NULL); + DImpactDecal::StaticCreate (s, trace.HitPos, trace.Line->sidedef[trace.Side], NULL); } } } diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 1c034b372..5b8ca293c 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -64,7 +64,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) return 0; // spawn a puff of smoke behind the rocket - P_SpawnPuff (self, PClass::FindActor(NAME_BulletPuff), self->X(), self->Y(), self->Z(), 0, 3); + P_SpawnPuff (self, PClass::FindActor(NAME_BulletPuff), self->Pos(), self->angle, self->angle, 3); smoke = Spawn ("RevenantTracerSmoke", self->Vec3Offset(-self->velx, -self->vely, 0), ALLOW_REPLACE); diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index ef7b3eb8c..d37250887 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -638,7 +638,7 @@ void DImpactDecal::CheckMax () } } -DImpactDecal *DImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color) +DImpactDecal *DImpactDecal::StaticCreate (const char *name, const fixedvec3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color) { if (cl_maxdecals > 0) { @@ -646,13 +646,13 @@ DImpactDecal *DImpactDecal::StaticCreate (const char *name, fixed_t x, fixed_t y if (tpl != NULL && (tpl = tpl->GetDecal()) != NULL) { - return StaticCreate (tpl, x, y, z, wall, ffloor, color); + return StaticCreate (tpl, pos, wall, ffloor, color); } } return NULL; } -DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color) +DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const fixedvec3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color) { DImpactDecal *decal = NULL; if (tpl != NULL && cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS)) @@ -666,16 +666,16 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x, // apply the custom color as well. if (tpl->ShadeColor != tpl_low->ShadeColor) lowercolor=0; else lowercolor = color; - StaticCreate (tpl_low, x, y, z, wall, ffloor, lowercolor); + StaticCreate (tpl_low, pos, wall, ffloor, lowercolor); } DImpactDecal::CheckMax(); - decal = new DImpactDecal (z); + decal = new DImpactDecal (pos.z); if (decal == NULL) { return NULL; } - if (!decal->StickToWall (wall, x, y, ffloor).isValid()) + if (!decal->StickToWall (wall, pos.x, pos.y, ffloor).isValid()) { return NULL; } @@ -692,7 +692,7 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, fixed_t x, } // Spread decal to nearby walls if it does not all fit on this one - decal->Spread (tpl, wall, x, y, z, ffloor); + decal->Spread (tpl, wall, pos.x, pos.y, pos.z, ffloor); } return decal; } @@ -779,22 +779,20 @@ DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t * { if (permanent) { - decal = new DBaseDecal(trace.Z); + decal = new DBaseDecal(trace.HitPos.z); wall = trace.Line->sidedef[trace.Side]; - decal->StickToWall(wall, trace.X, trace.Y, trace.ffloor); + decal->StickToWall(wall, trace.HitPos.x, trace.HitPos.y, trace.ffloor); tpl->ApplyToDecal(decal, wall); // Spread decal to nearby walls if it does not all fit on this one if (cl_spreaddecals) { - decal->Spread(tpl, wall, trace.X, trace.Y, trace.Z, trace.ffloor); + decal->Spread(tpl, wall, trace.HitPos.x, trace.HitPos.y, trace.HitPos.z, trace.ffloor); } return decal; } else { - return DImpactDecal::StaticCreate(tpl, - trace.X, trace.Y, trace.Z, - trace.Line->sidedef[trace.Side], NULL); + return DImpactDecal::StaticCreate(tpl, trace.HitPos, trace.Line->sidedef[trace.Side], NULL); } } return NULL; diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index cfbe4526b..1e59bf740 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -63,8 +63,8 @@ public: DImpactDecal (fixed_t z); DImpactDecal (side_t *wall, const FDecalTemplate *templ); - static DImpactDecal *StaticCreate (const char *name, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color=0); - static DImpactDecal *StaticCreate (const FDecalTemplate *tpl, fixed_t x, fixed_t y, fixed_t z, side_t *wall, F3DFloor * ffloor, PalEntry color=0); + static DImpactDecal *StaticCreate (const char *name, const fixedvec3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color=0); + static DImpactDecal *StaticCreate (const FDecalTemplate *tpl, const fixedvec3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color=0); void BeginPlay (); void Destroy (); diff --git a/src/p_local.h b/src/p_local.h index e1c12e652..47911f5f1 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -141,18 +141,18 @@ enum EPuffFlags PF_NORANDOMZ = 16 }; -AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); -inline AActor *P_SpawnPuff(AActor *source, PClassActor *pufftype, const fixedvec3 &pos, angle_t dir, int updown, int flags = 0, AActor *vict = NULL) +AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t hitdir, angle_t particledir, int updown, int flags = 0, AActor *vict = NULL); +inline AActor *P_SpawnPuff(AActor *source, PClassActor *pufftype, const fixedvec3 &pos, angle_t hitdir, angle_t particledir, int updown, int flags = 0, AActor *vict = NULL) { - return P_SpawnPuff(source, pufftype, pos.x, pos.y, pos.z, dir, updown, flags, vict); + return P_SpawnPuff(source, pufftype, pos.x, pos.y, pos.z, hitdir, particledir, updown, flags, vict); } void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); inline void P_SpawnBlood(const fixedvec3 &pos, angle_t dir, int damage, AActor *originator) { P_SpawnBlood(pos.x, pos.y, pos.z, dir, damage, originator); } -void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); -void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); +void P_BloodSplatter (fixedvec3 pos, AActor *originator); +void P_BloodSplatter2 (fixedvec3 pos, AActor *originator); void P_RipperBlood (AActor *mo, AActor *bleeder); int P_GetThingFloorType (AActor *thing); void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); @@ -328,12 +328,20 @@ enum // P_LineAttack flags AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); +inline void P_TraceBleed(int damage, const fixedvec3 &pos, AActor *target, angle_t angle, int pitch) +{ + P_TraceBleed(damage, pos.x, pos.y, pos.z, target, angle, pitch); +} void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff); // hitscan version void P_TraceBleed (int damage, AActor *target); // random direction version bool P_HitFloor (AActor *thing); bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false); +inline bool P_HitWater(AActor *thing, sector_t *sec, const fixedvec3 &pos, bool checkabove = false, bool alert = true, bool force = false) +{ + return P_HitWater(thing, sec, pos.x, pos.y, pos.z, checkabove, alert, force); +} void P_CheckSplash(AActor *self, fixed_t distance); void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, PClassActor *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, PClassActor *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun diff --git a/src/p_map.cpp b/src/p_map.cpp index a0ecc58f7..15718ec4c 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -65,8 +65,7 @@ CVAR(Bool, cl_doautoaim, false, CVAR_ARCHIVE) static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, fixedvec2 * posforwindowcheck = NULL); static void SpawnShootDecal(AActor *t1, const FTraceResults &trace); -static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff, - fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz, bool ffloor = false); +static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff); static FRandom pr_tracebleed("TraceBleed"); static FRandom pr_checkthing("CheckThing"); @@ -245,7 +244,7 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLines if (open.top < tmf.ceilingz) { tmf.ceilingz = open.top; - if (open.topsec != NULL) tmf.floorsector = open.topsec; + if (open.topsec != NULL) tmf.ceilingsector = open.topsec; if (ffcf_verbose) Printf(" Adjust ceilingz to %f\n", FIXED2FLOAT(open.top)); mit.StopUp(); } @@ -1527,7 +1526,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch !(tm.thing->flags3 & MF3_BLOODLESSIMPACT) && (pr_checkthing() < 192)) { - P_BloodSplatter(tm.thing->X(), tm.thing->Y(), tm.thing->Z(), thing); + P_BloodSplatter(tm.thing->Pos(), thing); } if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) { @@ -3667,7 +3666,7 @@ struct aim_t void EnterSectorPortal(int position, fixed_t frac, sector_t *entersec, fixed_t newtoppitch, fixed_t newbottompitch) { AActor *portal = entersec->SkyBoxes[position]; - if (portal == NULL) + if (position == sector_t::ceiling && portal->threshold < limitz) return; else if (position == sector_t::floor && portal->threshold > limitz) return; aim_t newtrace = Clone(); @@ -3779,7 +3778,7 @@ struct aim_t if (aimdebug) Printf("Start AimTraverse, start = %f,%f,%f, vect = %f,%f,%f\n", - startpos.x / 65536., startpos.y / 65536., startpos.y / 65536., + startpos.x / 65536., startpos.y / 65536., startpos.z / 65536., aimtrace.x / 65536., aimtrace.y / 65536.); while ((in = it.Next())) @@ -4102,7 +4101,7 @@ fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, FTranslated //========================================================================== // -// +// Helper stuff for P_LineAttack // //========================================================================== @@ -4231,7 +4230,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, } if (puffDefaults != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { // Spawn the puff anyway - puff = P_SpawnPuff(t1, pufftype, trace.X, trace.Y, trace.Z, angle - ANG180, 2, puffFlags); + puff = P_SpawnPuff(t1, pufftype, trace.HitPos, trace.SrcAngleToTarget, trace.SrcAngleToTarget, 2, puffFlags); } else { @@ -4240,21 +4239,19 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, } else { - fixed_t hitx = 0, hity = 0, hitz = 0; - if (trace.HitType != TRACE_HitActor) { // position a bit closer for puffs if (trace.HitType != TRACE_HitWall || trace.Line->special != Line_Horizon) { - fixed_t closer = trace.Distance - 4 * FRACUNIT; - fixedvec2 pos = t1->Vec2Offset(FixedMul(vx, closer), FixedMul(vy, closer)); - puff = P_SpawnPuff(t1, pufftype, pos.x, pos.y, - shootz + FixedMul(vz, closer), angle - ANG90, 0, puffFlags); + fixedvec2 pos = P_GetOffsetPosition(trace.HitPos.x, trace.HitPos.y, -trace.HitVector.x * 4, -trace.HitVector.y * 4); + puff = P_SpawnPuff(t1, pufftype, pos.x, pos.y, trace.HitPos.z - trace.HitVector.z * 4, trace.SrcAngleToTarget, + trace.SrcAngleToTarget - ANGLE_90, 0, puffFlags); + puff->radius = 1; } // [RH] Spawn a decal - if (trace.HitType == TRACE_HitWall && trace.Line->special != Line_Horizon && !(flags & LAF_NOIMPACTDECAL) && !(puffDefaults->flags7 & MF7_NODECAL)) + if (trace.HitType == TRACE_HitWall && trace.Line->special != Line_Horizon && !trace.Line->isVisualPortal() && !(flags & LAF_NOIMPACTDECAL) && !(puffDefaults->flags7 & MF7_NODECAL)) { // [TN] If the actor or weapon has a decal defined, use that one. if (t1->DecalGenerator != NULL || @@ -4283,7 +4280,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, trace.Sector->heightsec == NULL && trace.HitType == TRACE_HitFloor) { - P_HitWater(puff, trace.Sector, trace.X, trace.Y, trace.Z); + P_HitWater(puff, trace.Sector, trace.HitPos); } } else @@ -4297,14 +4294,13 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, (t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD)); // Hit a thing, so it could be either a puff or blood - fixed_t dist = trace.Distance; + fixedvec3 bleedpos = trace.HitPos; // position a bit closer for puffs/blood if using compatibility mode. - if (i_compatflags & COMPATF_HITSCAN) dist -= 10 * FRACUNIT; - hitx = t1->X() + FixedMul(vx, dist); - hity = t1->Y() + FixedMul(vy, dist); - hitz = shootz + FixedMul(vz, dist); - - + if (i_compatflags & COMPATF_HITSCAN) + { + fixedvec2 ofs = P_GetOffsetPosition(bleedpos.x, bleedpos.y, -10 * trace.HitVector.x, -10 * trace.HitVector.y); + bleedpos -= { ofs.x, ofs.y, -10 * trace.HitVector.z}; + } // Spawn bullet puffs or blood spots, depending on target type. if ((puffDefaults != NULL && puffDefaults->flags3 & MF3_PUFFONACTORS) || @@ -4315,7 +4311,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, puffFlags |= PF_HITTHINGBLEED; // We must pass the unreplaced puff type here - puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING, trace.Actor); + puff = P_SpawnPuff(t1, pufftype, bleedpos, trace.SrcAngleToTarget, trace.SrcAngleToTarget - ANGLE_90, 2, puffFlags | PF_HITTHING, trace.Actor); } // Allow puffs to inflict poison damage, so that hitscans can poison, too. @@ -4341,11 +4337,10 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, { // Since the puff is the damage inflictor we need it here // regardless of whether it is displayed or not. - puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING | PF_TEMPORARY); + puff = P_SpawnPuff(t1, pufftype, bleedpos, 0, 0, 2, puffFlags | PF_HITTHING | PF_TEMPORARY); killPuff = true; } -#pragma message("damage angle") - newdam = P_DamageMobj(trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags); + newdam = P_DamageMobj(trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags|DMG_USEANGLE, trace.SrcAngleToTarget); if (actualdamage != NULL) { *actualdamage = newdam; @@ -4357,7 +4352,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, !(trace.Actor->flags & MF_NOBLOOD) && !(trace.Actor->flags2 & (MF2_INVULNERABLE | MF2_DORMANT))) { - P_SpawnBlood(hitx, hity, hitz, angle - ANG180, newdam > 0 ? newdam : damage, trace.Actor); + P_SpawnBlood(bleedpos, trace.SrcAngleToTarget, newdam > 0 ? newdam : damage, trace.Actor); } if (damage) @@ -4369,35 +4364,34 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, { if (axeBlood) { - P_BloodSplatter2(hitx, hity, hitz, trace.Actor); + P_BloodSplatter2(bleedpos, trace.Actor); } if (pr_lineattack() < 192) { - P_BloodSplatter(hitx, hity, hitz, trace.Actor); + P_BloodSplatter(bleedpos, trace.Actor); } } } // [RH] Stick blood to walls - P_TraceBleed(newdam > 0 ? newdam : damage, trace.X, trace.Y, trace.Z, - trace.Actor, srcangle, srcpitch); + P_TraceBleed(newdam > 0 ? newdam : damage, trace.HitPos, + trace.Actor, trace.SrcAngleToTarget, srcpitch); } } if (victim != NULL) { victim->linetarget = trace.Actor; - victim->angleFromSource = R_PointToAngle2(t1->X(), t1->Y(), trace.Actor->X(), trace.Actor->Y()); - victim->unlinked = false; + victim->angleFromSource = trace.SrcAngleToTarget; + victim->unlinked = trace.unlinked; } } if (trace.Crossed3DWater || trace.CrossedWater) { - if (puff == NULL) { // Spawn puff just to get a mass for the splash - puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING | PF_TEMPORARY); + puff = P_SpawnPuff(t1, pufftype, trace.HitPos, 0, 0, 2, puffFlags | PF_HITTHING | PF_TEMPORARY); killPuff = true; } - SpawnDeepSplash(t1, trace, puff, vx, vy, vz, shootz, trace.Crossed3DWater != NULL); + SpawnDeepSplash(t1, trace, puff); } } if (killPuff && puff != NULL) @@ -4553,11 +4547,8 @@ void P_TraceBleed(int damage, fixed_t x, fixed_t y, fixed_t z, AActor *actor, an bloodcolor.a = 1; } - DImpactDecal::StaticCreate(bloodType, - bleedtrace.X, bleedtrace.Y, bleedtrace.Z, - bleedtrace.Line->sidedef[bleedtrace.Side], - bleedtrace.ffloor, - bloodcolor); + DImpactDecal::StaticCreate(bloodType, bleedtrace.HitPos, + bleedtrace.Line->sidedef[bleedtrace.Side], bleedtrace.ffloor, bloodcolor); } } } @@ -4645,7 +4636,8 @@ void P_TraceBleed(int damage, AActor *target) struct SRailHit { AActor *HitActor; - fixed_t Distance; + fixedvec3 HitPos; + angle_t HitAngle; }; struct RailData { @@ -4679,7 +4671,13 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata) // Save this thing for damaging later, and continue the trace SRailHit newhit; newhit.HitActor = res.Actor; - newhit.Distance = res.Distance - 10 * FRACUNIT; // put blood in front + newhit.HitPos = res.HitPos; + newhit.HitAngle = res.SrcAngleToTarget; + if (i_compatflags & COMPATF_HITSCAN) + { + fixedvec2 ofs = P_GetOffsetPosition(newhit.HitPos.x, newhit.HitPos.y, -10 * res.HitVector.x, -10 * res.HitVector.y); + newhit.HitPos = { ofs.x, ofs.y, -10 * res.HitVector.z}; + } data->RailHits.Push(newhit); return data->StopAtOne ? TRACE_Stop : TRACE_Continue; @@ -4761,17 +4759,13 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i { - fixed_t x, y, z; bool spawnpuff; bool bleed = false; int puffflags = PF_HITTHING; AActor *hitactor = rail_data.RailHits[i].HitActor; - fixed_t hitdist = rail_data.RailHits[i].Distance; - - x = xy.x + FixedMul(hitdist, vx); - y = xy.y + FixedMul(hitdist, vy); - z = shootz + FixedMul(hitdist, vz); + fixedvec3 &hitpos = rail_data.RailHits[i].HitPos; + angle_t hitangle = rail_data.RailHits[i].HitAngle; if ((hitactor->flags & MF_NOBLOOD) || (hitactor->flags2 & MF2_DORMANT || ((hitactor->flags2 & MF2_INVULNERABLE) && !(puffDefaults->flags3 & MF3_FOILINVUL)))) @@ -4789,7 +4783,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i } if (spawnpuff) { - P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags, hitactor); + P_SpawnPuff(source, puffclass, hitpos, trace.SrcAngleToTarget, trace.SrcAngleToTarget - ANGLE_90, 1, puffflags, hitactor); } int dmgFlagPass = DMG_INFLICTOR_IS_PUFF; @@ -4802,13 +4796,12 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i if (puffDefaults->flags3 & MF3_FOILINVUL) dmgFlagPass |= DMG_FOILINVUL; if (puffDefaults->flags7 & MF7_FOILBUDDHA) dmgFlagPass |= DMG_FOILBUDDHA; } -#pragma message("damage angle") - int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass); + int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass|DMG_USEANGLE, hitangle); if (bleed) { - P_SpawnBlood(x, y, z, (source->angle + angleoffset) - ANG180, newdam > 0 ? newdam : damage, hitactor); - P_TraceBleed(newdam > 0 ? newdam : damage, x, y, z, hitactor, source->angle, pitch); + P_SpawnBlood(hitpos, hitangle, newdam > 0 ? newdam : damage, hitactor); + P_TraceBleed(newdam > 0 ? newdam : damage, hitpos, hitactor, source->angle, pitch); } } @@ -4819,7 +4812,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { - puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); + puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleToTarget, trace.SrcAngleToTarget - ANGLE_90, 1, 0); if (puff && (trace.Line != NULL) && (trace.Line->special == Line_Horizon) && !(puff->flags3 & MF3_SKYEXPLODE)) puff->Destroy(); } @@ -4834,7 +4827,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i AActor* puff = NULL; if (puffclass != NULL && puffDefaults->flags3 & MF3_ALWAYSPUFF) { - puff = P_SpawnPuff(source, puffclass, trace.X, trace.Y, trace.Z, (source->angle + angleoffset) - ANG90, 1, 0); + puff = P_SpawnPuff(source, puffclass, trace.HitPos, trace.SrcAngleToTarget, trace.SrcAngleToTarget - ANGLE_90, 1, 0); if (puff && !(puff->flags3 & MF3_SKYEXPLODE) && (((trace.HitType == TRACE_HitFloor) && (puff->floorpic == skyflatnum)) || ((trace.HitType == TRACE_HitCeiling) && (puff->ceilingpic == skyflatnum)))) @@ -4845,23 +4838,21 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i } if (thepuff != NULL) { - if (trace.HitType == TRACE_HitFloor && - trace.CrossedWater == NULL && - trace.Sector->heightsec == NULL) - { - P_HitWater(thepuff, trace.Sector, trace.X, trace.Y, trace.Z); - } if (trace.Crossed3DWater || trace.CrossedWater) { - SpawnDeepSplash(source, trace, thepuff, vx, vy, vz, shootz, trace.Crossed3DWater != NULL); + SpawnDeepSplash(source, trace, thepuff); + } + else if (trace.HitType == TRACE_HitFloor && trace.Sector->heightsec == NULL) + { + P_HitWater(thepuff, trace.Sector, trace.HitPos); } thepuff->Destroy(); } // Draw the slug's trail. - end.X = FIXED2DBL(trace.X); - end.Y = FIXED2DBL(trace.Y); - end.Z = FIXED2DBL(trace.Z); + end.X = FIXED2DBL(trace.HitPos.x); + end.Y = FIXED2DBL(trace.HitPos.y); + end.Z = FIXED2DBL(trace.HitPos.z); P_DrawRailTrail(source, start, end, color1, color2, maxdiff, railflags, spawnclass, source->angle + angleoffset, duration, sparsity, drift, SpiralOffset); } @@ -4900,9 +4891,9 @@ void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &Camera } else { - CameraX = trace.X; - CameraY = trace.Y; - CameraZ = trace.Z; + CameraX = trace.HitPos.x; + CameraY = trace.HitPos.y; + CameraZ = trace.HitPos.z; } CameraSector = trace.Sector; unlinked = trace.unlinked; @@ -6426,7 +6417,7 @@ void SpawnShootDecal(AActor *t1, const FTraceResults &trace) if (decalbase != NULL) { DImpactDecal::StaticCreate(decalbase->GetDecal(), - trace.X, trace.Y, trace.Z, trace.Line->sidedef[trace.Side], trace.ffloor); + trace.HitPos, trace.Line->sidedef[trace.Side], trace.ffloor); } } @@ -6436,31 +6427,20 @@ void SpawnShootDecal(AActor *t1, const FTraceResults &trace) // //========================================================================== -static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff, - fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz, bool ffloor) +static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff) { - const secplane_t *plane; - if (ffloor && trace.Crossed3DWater) - plane = trace.Crossed3DWater->top.plane; + const fixedvec3 *hitpos; + if (trace.Crossed3DWater) + { + hitpos = &trace.Crossed3DWaterPos; + } else if (trace.CrossedWater && trace.CrossedWater->heightsec) - plane = &trace.CrossedWater->heightsec->floorplane; + { + hitpos = &trace.CrossedWaterPos; + } else return; - fixed_t num, den, hitdist; - den = TMulScale16(plane->a, vx, plane->b, vy, plane->c, vz); - if (den != 0) - { - num = TMulScale16(plane->a, t1->X(), plane->b, t1->Y(), plane->c, shootz) + plane->d; - hitdist = FixedDiv(-num, den); - - if (hitdist >= 0 && hitdist <= trace.Distance) - { - fixedvec2 hitpos = t1->Vec2Offset(FixedMul(vx, hitdist), FixedMul(vy, hitdist)); - fixed_t hitz = shootz + FixedMul(vz, hitdist); - - P_HitWater(puff != NULL ? puff : t1, P_PointInSector(hitpos.x, hitpos.y), hitpos.x, hitpos.y, hitz); - } - } + P_HitWater(puff != NULL ? puff : t1, P_PointInSector(hitpos->x, hitpos->y), *hitpos); } //============================================================================= diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 70ea6a0b9..aa3691afa 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1444,8 +1444,7 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target) } } - DImpactDecal::StaticCreate (base->GetDecal (), - x, y, z, line->sidedef[side], ffloor); + DImpactDecal::StaticCreate(base->GetDecal(), { x, y, z }, line->sidedef[side], ffloor); } } } @@ -5228,7 +5227,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // P_SpawnPuff // -AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags, AActor *vict) +AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t hitdir, angle_t particledir, int updown, int flags, AActor *vict) { AActor *puff; @@ -5256,8 +5255,8 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y if ( puff && (puff->flags5 & MF5_PUFFGETSOWNER)) puff->target = source; - - if (source != NULL) puff->angle = puff->AngleTo(source); + // Angle is the opposite of the hit direction (i.e. the puff faces the source.) + puff->angle = hitdir + ANGLE_180; // If a puff has a crash state and an actor was not hit, // it will enter the crash state. This is used by the StrifeSpark @@ -5282,7 +5281,7 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y { if (cl_pufftype && updown != 3 && (puff->flags4 & MF4_ALLOWPARTICLES)) { - P_DrawSplash2 (32, x, y, z, dir, updown, 1); + P_DrawSplash2 (32, x, y, z, particledir, updown, 1); puff->renderflags |= RF_INVISIBLE; } @@ -5402,7 +5401,7 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc // //--------------------------------------------------------------------------- -void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) +void P_BloodSplatter (fixedvec3 pos, AActor *originator) { PalEntry bloodcolor = originator->GetBloodColor(); PClassActor *bloodcls = originator->GetBloodType(1); @@ -5416,7 +5415,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { AActor *mo; - mo = Spawn(bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement + mo = Spawn(bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement mo->target = originator; mo->velx = pr_splatter.Random2 () << 10; mo->vely = pr_splatter.Random2 () << 10; @@ -5432,7 +5431,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) } if (bloodtype >= 1) { - P_DrawSplash2 (40, x, y, z, 0u - originator->AngleTo(x, y), 2, bloodcolor); + P_DrawSplash2 (40, pos.x, pos.y, pos.z, 0u - originator->AngleTo(pos), 2, bloodcolor); } } @@ -5442,7 +5441,7 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) // //=========================================================================== -void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) +void P_BloodSplatter2 (fixedvec3 pos, AActor *originator) { PalEntry bloodcolor = originator->GetBloodColor(); PClassActor *bloodcls = originator->GetBloodType(2); @@ -5456,10 +5455,10 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { AActor *mo; - x += ((pr_splat()-128)<<11); - y += ((pr_splat()-128)<<11); + pos.x += ((pr_splat()-128)<<11); + pos.y += ((pr_splat()-128)<<11); - mo = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement + mo = Spawn (bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement mo->target = originator; // colorize the blood! @@ -5472,7 +5471,7 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) } if (bloodtype >= 1) { - P_DrawSplash2 (100, x, y, z, 0u - originator->AngleTo(x, y), 2, bloodcolor); + P_DrawSplash2 (100, pos.x, pos.y, pos.z, 0u - originator->AngleTo(pos), 2, bloodcolor); } } @@ -5733,7 +5732,7 @@ bool P_HitFloor (AActor *thing) { if (rover->top.plane->ZatPoint(pos.x, pos.y) == thing->Z()) { - return P_HitWater (thing, m->m_sector, pos.x, pos.y, pos.z); + return P_HitWater (thing, m->m_sector, pos); } } } @@ -5743,7 +5742,7 @@ bool P_HitFloor (AActor *thing) return false; } - return P_HitWater (thing, m->m_sector, pos.x, pos.y, pos.z); + return P_HitWater (thing, m->m_sector, pos); } //--------------------------------------------------------------------------- diff --git a/src/p_trace.cpp b/src/p_trace.cpp index ad2bb269c..2e96db7c9 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -87,11 +87,18 @@ struct FTraceInfo return CheckPlane(checkFloor ? sector->floorplane : sector->ceilingplane); } - bool FTraceInfo::Check3DFloorPlane(const F3DFloor *ffloor, bool checkBottom) + bool Check3DFloorPlane(const F3DFloor *ffloor, bool checkBottom) { return CheckPlane(checkBottom? *(ffloor->bottom.plane) : *(ffloor->top.plane)); } + void SetSourcePosition() + { + Results->SrcFromTarget = { StartX, StartY, StartZ }; + Results->HitVector = { Vx, Vy, Vz }; + Results->SrcAngleToTarget = R_PointToAngle2(0, 0, Results->HitPos.x - StartX, Results->HitPos.y - StartY); + } + }; @@ -227,7 +234,7 @@ void FTraceInfo::EnterSectorPortal(int position, fixed_t frac, sector_t *enterse if (newtrace.TraceTraverse(ActorMask ? PT_ADDLINES | PT_ADDTHINGS | PT_COMPATIBLE : PT_ADDLINES)) { - Results->CopyIfCloser(TempResults); + TempResults->CopyIfCloser(newtrace.Results); } } @@ -319,7 +326,7 @@ void FTraceInfo::Setup3DFloors() if (Check3DFloorPlane(rover, false)) { Results->Crossed3DWater = rover; - Results->Crossed3DWaterPos = { Results->X, Results->Y, Results->Z }; + Results->Crossed3DWaterPos = Results->HitPos; } } @@ -468,7 +475,7 @@ bool FTraceInfo::LineCheck(intercept_t *in) if (CheckSectorPlane(hsec, true)) { Results->CrossedWater = §ors[CurSector->sectornum]; - Results->CrossedWaterPos = { Results->X, Results->Y, Results->Z }; + Results->CrossedWaterPos = Results->HitPos; } } @@ -645,9 +652,8 @@ cont: if (Results->HitType == TRACE_HitWall) { - Results->X = hitx; - Results->Y = hity; - Results->Z = hitz; + Results->HitPos = { hitx, hity, hitz }; + SetSourcePosition(); Results->Distance = dist; Results->Fraction = in->frac; Results->Line = in->d.line; @@ -773,9 +779,8 @@ cont1: Results->HitType = TRACE_HitActor; - Results->X = hitx; - Results->Y = hity; - Results->Z = hitz; + Results->HitPos = { hitx, hity, hitz }; + SetSourcePosition(); Results->Distance = dist; Results->Fraction = in->frac; Results->Actor = in->d.thing; @@ -823,7 +828,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) if (Check3DFloorPlane(rover, false)) { Results->Crossed3DWater = rover; - Results->Crossed3DWaterPos = { Results->X, Results->Y, Results->Z }; + Results->Crossed3DWaterPos = Results->HitPos; } } } @@ -852,7 +857,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) // 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->X, Results->Y) >= Results->Z) + CurSector->heightsec->floorplane.ZatPoint(Results->HitPos) >= Results->HitPos.z) { // Save the result so that the water check doesn't destroy it. FTraceResults *res = Results; @@ -862,7 +867,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) if (CheckSectorPlane(CurSector->heightsec, true)) { Results->CrossedWater = §ors[CurSector->sectornum]; - Results->CrossedWaterPos = { Results->X, Results->Y, Results->Z }; + Results->CrossedWaterPos = Results->HitPos; } Results = res; } @@ -889,7 +894,7 @@ bool FTraceInfo::TraceTraverse (int ptflags) if (Results->CrossedWater == NULL && CurSector->heightsec != NULL && - CurSector->heightsec->floorplane.ZatPoint(Results->X, Results->Y) >= Results->Z) + CurSector->heightsec->floorplane.ZatPoint(Results->HitPos) >= Results->HitPos.z) { // Save the result so that the water check doesn't destroy it. FTraceResults *res = Results; @@ -899,15 +904,17 @@ bool FTraceInfo::TraceTraverse (int ptflags) if (CheckSectorPlane(CurSector->heightsec, true)) { Results->CrossedWater = §ors[CurSector->sectornum]; - Results->CrossedWaterPos = { Results->X, Results->Y, Results->Z }; + Results->CrossedWaterPos = Results->HitPos; } Results = res; } if (Results->HitType == TRACE_HitNone && Results->Distance == 0) { - Results->X = StartX + FixedMul(Vx, MaxDist); - Results->Y = StartY + FixedMul(Vy, MaxDist); - Results->Z = StartZ + FixedMul(Vz, MaxDist); + Results->HitPos = { + StartX + FixedMul(Vx, MaxDist), + StartY + FixedMul(Vy, MaxDist), + StartZ + FixedMul(Vz, MaxDist) }; + SetSourcePosition(); Results->Distance = MaxDist; Results->Fraction = FRACUNIT; } @@ -934,9 +941,11 @@ bool FTraceInfo::CheckPlane (const secplane_t &plane) if (hitdist > EnterDist && hitdist < MaxDist) { - Results->X = StartX + FixedMul (Vx, hitdist); - Results->Y = StartY + FixedMul (Vy, hitdist); - Results->Z = StartZ + FixedMul (Vz, hitdist); + Results->HitPos = { + StartX + FixedMul(Vx, hitdist), + StartY + FixedMul(Vy, hitdist), + StartZ + FixedMul(Vz, hitdist) }; + SetSourcePosition(); Results->Distance = hitdist; Results->Fraction = FixedDiv (hitdist, MaxDist); return true; diff --git a/src/p_trace.h b/src/p_trace.h index 641a8c007..43203f035 100644 --- a/src/p_trace.h +++ b/src/p_trace.h @@ -65,7 +65,8 @@ struct FTraceResults { sector_t *Sector; FTextureID HitTexture; - fixed_t X, Y, Z; + fixedvec3 HitPos; + fixedvec3 HitVector; fixedvec3 SrcFromTarget; angle_t SrcAngleToTarget; diff --git a/src/portal.cpp b/src/portal.cpp index 6f0baeaea..e37697944 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -1078,11 +1078,6 @@ void P_CreateLinkedPortals() // //============================================================================ - -static bool ProcessLayer() -{ -} - bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out) { // Keep this temporary work stuff static. This function can never be called recursively diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index db1f722f1..42863b3aa 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5178,7 +5178,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_WolfAttack) if ((0 && dpuff->flags3 & MF3_PUFFONACTORS) || !spawnblood) { spawnblood = false; - P_SpawnPuff(self, pufftype, bloodpos, angle, 0); + P_SpawnPuff(self, pufftype, bloodpos, angle, angle, 0); } } else if (self->target->flags3 & MF3_GHOST) From 7d7112f42719f2fabc0da7faf1d796d6e6777950 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Mar 2016 00:17:52 +0100 Subject: [PATCH 08/27] - added portal support to A_ThrustImpale, P_PushUp and P_PushDown. --- src/actor.h | 6 ------ src/g_hexen/a_spike.cpp | 26 +++++++++++++++++--------- src/p_map.cpp | 29 ++++++++++++++++++----------- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/actor.h b/src/actor.h index b5b32611c..344f5c267 100644 --- a/src/actor.h +++ b/src/actor.h @@ -813,12 +813,6 @@ public: return bloodcls; } - bool intersects(AActor *other) const - { - fixed_t blockdist = radius + other->radius; - return ( abs(X() - other->X()) < blockdist && abs(Y() - other->Y()) < blockdist); - } - fixed_t AproxDistance(fixed_t otherx, fixed_t othery) { return P_AproxDistance(X() - otherx, Y() - othery); diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp index 0987d48d9..10444ecb9 100644 --- a/src/g_hexen/a_spike.cpp +++ b/src/g_hexen/a_spike.cpp @@ -153,24 +153,32 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale) { PARAM_ACTION_PROLOGUE; - AActor *thing; // This doesn't need to iterate through portals. - FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), self->radius)); - while ((thing = it.Next())) + + FPortalGroupArray check; + FMultiBlockThingsIterator it(check, self); + FMultiBlockThingsIterator::CheckResult cres; + while (it.Next(&cres)) { - if (!thing->intersects(self)) - { + fixed_t blockdist = self->radius + cres.thing->radius; + if (abs(self->X() - cres.position.x) >= blockdist || abs(self->Y() - cres.position.y) >= blockdist) continue; + + // Q: Make this z-aware for everything? It never was before. + if (cres.thing->Top() < self->Z() || cres.thing->Z() > self->Top()) + { + if (self->Sector->PortalGroup != cres.thing->Sector->PortalGroup) + continue; } - if (!(thing->flags & MF_SHOOTABLE) ) + if (!(cres.thing->flags & MF_SHOOTABLE) ) continue; - if (thing == self) + if (cres.thing == self) continue; // don't clip against self - int newdam = P_DamageMobj (thing, self, self, 10001, NAME_Crush); - P_TraceBleed (newdam > 0 ? newdam : 10001, thing); + int newdam = P_DamageMobj (cres.thing, self, self, 10001, NAME_Crush); + P_TraceBleed (newdam > 0 ? newdam : 10001, cres.thing); self->args[1] = 1; // Mark thrust thing as bloody } return 0; diff --git a/src/p_map.cpp b/src/p_map.cpp index 15718ec4c..3470de394 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5513,14 +5513,16 @@ void P_FindAboveIntersectors(AActor *actor) if (!(actor->flags & MF_SOLID)) return; - AActor *thing; - FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); - while ((thing = it.Next())) + FPortalGroupArray check; + FMultiBlockThingsIterator it(check, actor); + FMultiBlockThingsIterator::CheckResult cres; + while (it.Next(&cres)) { - if (!thing->intersects(actor)) - { + AActor *thing = cres.thing; + fixed_t blockdist = actor->radius + thing->radius; + if (abs(actor->X() - cres.position.x) >= blockdist || abs(actor->Y() - cres.position.y) >= blockdist) continue; - } + if (!(thing->flags & MF_SOLID)) { // Can't hit thing continue; @@ -5568,13 +5570,16 @@ void P_FindBelowIntersectors(AActor *actor) return; AActor *thing; - FBlockThingsIterator it(FBoundingBox(actor->X(), actor->Y(), actor->radius)); - while ((thing = it.Next())) + FPortalGroupArray check; + FMultiBlockThingsIterator it(check, actor); + FMultiBlockThingsIterator::CheckResult cres; + while (it.Next(&cres)) { - if (!thing->intersects(actor)) - { + AActor *thing = cres.thing; + fixed_t blockdist = actor->radius + thing->radius; + if (abs(actor->X() - cres.position.x) >= blockdist || abs(actor->Y() - cres.position.y) >= blockdist) continue; - } + if (!(thing->flags & MF_SOLID)) { // Can't hit thing continue; @@ -5718,6 +5723,7 @@ int P_PushUp(AActor *thing, FChangePosition *cpos) return 2; } } + thing->CheckPortalTransition(true); return 0; } @@ -5765,6 +5771,7 @@ int P_PushDown(AActor *thing, FChangePosition *cpos) } } } + thing->CheckPortalTransition(true); return 0; } From 8f71906fc3f1bb75530ac6f90f5a7499ab05d381 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Mar 2016 01:02:48 +0100 Subject: [PATCH 09/27] - added portal support to P_RadiusAttack. This currently only works for linked portals. For other types some major refactoring may be necessary because it not only requires multiple passes of P_RadiusAttack but also an alteration of how sight checks work. --- src/p_map.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 3470de394..1c8d9b466 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5245,6 +5245,10 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo double bombdistancefloat = 1.f / (double)(bombdistance - fulldamagedistance); double bombdamagefloat = (double)bombdamage; + FPortalGroupArray grouplist; + FMultiBlockThingsIterator it(grouplist, bombspot->X(), bombspot->Y(), bombspot->Z() - (bombdistance<height + (bombdistance*2)<X(), bombspot->Y(), bombdistance << FRACBITS)); AActor *thing; @@ -5253,8 +5257,9 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo bombsource = bombspot; } - while ((thing = it.Next())) + while ((it.Next(&cres))) { + AActor *thing = cres.thing; // Vulnerable actors can be damaged by radius attacks even if not shootable // Used to emulate MBF's vulnerability of non-missile bouncers to explosions. if (!((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE))) From 13a7507c4d0a5c04378009086a5a87528563fa6b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Mar 2016 01:48:13 +0100 Subject: [PATCH 10/27] - should have saved that... --- src/p_map.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 1c8d9b466..468fff5b3 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5246,12 +5246,9 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo double bombdamagefloat = (double)bombdamage; FPortalGroupArray grouplist; - FMultiBlockThingsIterator it(grouplist, bombspot->X(), bombspot->Y(), bombspot->Z() - (bombdistance<height + (bombdistance*2)<X(), bombspot->Y(), bombspot->Z() - (bombdistance<height + ((bombdistance*2)<X(), bombspot->Y(), bombdistance << FRACBITS)); - AActor *thing; - if (flags & RADF_SOURCEISSPOT) { // The source is actually the same as the spot, even if that wasn't what we received. bombsource = bombspot; From 72edd7d4555c4f61da67b0787e252f3402e913f1 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 6 Mar 2016 22:17:30 -0600 Subject: [PATCH 11/27] Fixed: GetVarAddrType() bounds check was inverted --- src/p_acs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index b8976955b..466d8793e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4546,7 +4546,7 @@ bool GetVarAddrType(AActor *self, FName varname, int index, void *&addr, PType * // unwrap contained type type = arraytype->ElementType; // offset by index (if in bounds) - if ((unsigned)index < arraytype->ElementCount) + if ((unsigned)index >= arraytype->ElementCount) { // out of bounds return false; } From a65b0d7d4c79c0c696a1929b5a5f62873d44877e Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Fri, 4 Mar 2016 15:42:51 +0100 Subject: [PATCH 12/27] - Fixed misaligned pointer access error in zipdir. It happens if zipdir is compiled with GCC/Clang UBSan and is run on an already existing zdoom.pk3. --- tools/zipdir/zipdir.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/zipdir/zipdir.c b/tools/zipdir/zipdir.c index b331021d1..cb43f5f82 100644 --- a/tools/zipdir/zipdir.c +++ b/tools/zipdir/zipdir.c @@ -232,6 +232,9 @@ int Quiet; // PRIVATE DATA DEFINITIONS ------------------------------------------------ +static const UINT32 centralfile = ZIP_CENTRALFILE; +static const UINT32 endofdir = ZIP_ENDOFDIR; + static int no_mem; static ISzAlloc Alloc = { SzAlloc, SzFree }; @@ -1305,7 +1308,8 @@ int compress_ppmd(Byte *out, unsigned int *outlen, const Byte *in, unsigned int return -1; } - *(short *)out = LittleShort((maxorder - 1) + ((sasize - 1) << 4) + (cutoff << 12)); + const short outval = LittleShort((maxorder - 1) + ((sasize - 1) << 4) + (cutoff << 12)); + memcpy(out, (const Byte *)&outval, sizeof(short)); *outlen = *outlen - ppsout.buffersize; return 0; } @@ -1420,12 +1424,12 @@ BYTE *find_central_dir(FILE *fin) free(dir); return NULL; } - if (*(UINT32 *)dir != ZIP_CENTRALFILE) + if (memcmp(dir, (const BYTE *)¢ralfile, sizeof(UINT32)) != 0) { free(dir); return NULL; } - *(UINT32 *)(dir + LittleLong(eod.DirectorySize)) = ZIP_ENDOFDIR; + memcpy(dir + LittleLong(eod.DirectorySize), (const BYTE *)&endofdir, sizeof(UINT32)); return dir; } @@ -1444,7 +1448,7 @@ CentralDirectoryEntry *find_file_in_zip(BYTE *dir, const char *path, unsigned in CentralDirectoryEntry *ent; int flags; - while (*(UINT32 *)dir == ZIP_CENTRALFILE) + while (memcmp(dir, (const BYTE *)¢ralfile, sizeof(UINT32)) == 0) { ent = (CentralDirectoryEntry *)dir; if (pathlen == LittleShort(ent->NameLength) && @@ -1455,7 +1459,7 @@ CentralDirectoryEntry *find_file_in_zip(BYTE *dir, const char *path, unsigned in } dir += sizeof(*ent) + LittleShort(ent->NameLength) + LittleShort(ent->ExtraLength) + LittleShort(ent->CommentLength); } - if (*(UINT32 *)dir != ZIP_CENTRALFILE) + if (memcmp(dir, (const BYTE *)¢ralfile, sizeof(UINT32)) != 0) { return NULL; } From fe4bc31d59e4d6b5743227926dbb37f2d4466def Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Mar 2016 11:36:51 +0100 Subject: [PATCH 13/27] - fixed some bad offset calculations. --- src/p_map.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index 468fff5b3..e3ed9329f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4299,7 +4299,9 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, if (i_compatflags & COMPATF_HITSCAN) { fixedvec2 ofs = P_GetOffsetPosition(bleedpos.x, bleedpos.y, -10 * trace.HitVector.x, -10 * trace.HitVector.y); - bleedpos -= { ofs.x, ofs.y, -10 * trace.HitVector.z}; + bleedpos.x = ofs.x; + bleedpos.y = ofs.y; + bleedpos.z -= -10 * trace.HitVector.z; } // Spawn bullet puffs or blood spots, depending on target type. @@ -4676,7 +4678,9 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata) if (i_compatflags & COMPATF_HITSCAN) { fixedvec2 ofs = P_GetOffsetPosition(newhit.HitPos.x, newhit.HitPos.y, -10 * res.HitVector.x, -10 * res.HitVector.y); - newhit.HitPos = { ofs.x, ofs.y, -10 * res.HitVector.z}; + newhit.HitPos.x = ofs.x; + newhit.HitPos.y = ofs.y; + newhit.HitPos.z -= -10 * res.HitVector.z; } data->RailHits.Push(newhit); From af50a79e551c55b806311c7142d133c56051501f Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Mon, 7 Mar 2016 09:02:34 -0600 Subject: [PATCH 14/27] - Fixed: ScaleY was not defaulting to ScaleX when specified as 0, which is how the behavior originally was in 2.8. This behavior can now be toggled with a new boolean, 'usezero'. --- src/thingdef/thingdef_codeptr.cpp | 3 ++- wadsrc/static/actors/actor.txt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 42863b3aa..084eebcf9 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2913,13 +2913,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetScale) PARAM_FIXED (scalex); PARAM_FIXED_OPT (scaley) { scaley = scalex; } PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } + PARAM_BOOL_OPT (usezero) { usezero = false; } AActor *ref = COPY_AAPTR(self, ptr); if (ref != NULL) { ref->scaleX = scalex; - ref->scaleY = scaley; + ref->scaleY = (!usezero && !scaley) ? scalex : scaley; } return 0; } diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index d8f20dfe5..b3401e834 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -207,7 +207,7 @@ ACTOR Actor native //: Thinker action native A_FadeIn(float reduce = 0.1, int flags = 0); action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true action native A_FadeTo(float target, float amount = 0.1, int flags = 0); - action native A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT); + action native A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false); action native A_SetMass(int mass); action native A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); action native A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, int size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1); From 8b9a0da5efe97ee0f8210cf41ba3c3da50789809 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 7 Mar 2016 09:58:52 -0600 Subject: [PATCH 15/27] That was hard to read --- src/thingdef/thingdef_codeptr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 084eebcf9..4cdf31747 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2919,8 +2919,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetScale) if (ref != NULL) { + if (scaley == 0 && !usezero) + { + scaley = scalex; + } ref->scaleX = scalex; - ref->scaleY = (!usezero && !scaley) ? scalex : scaley; + ref->scaleY = scaley; } return 0; } From e277fbe81d9ee45442d7d979042fc252a6cb2e11 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 7 Mar 2016 10:24:30 -0600 Subject: [PATCH 16/27] Fixed some incorrectness with some Hexen crushing specials - The following Hexen specials all stop 8 units above the floor: * Ceiling_CrushRaiseAndStay * Ceiling_CrushAndRaise * Ceiling_LowerAndCrush We only and Ceiling_LowerAndCrush correct. Clearly, I should have paid more attention when the Hexen source was released for the parts that I had already reverse engineered. --- src/p_ceiling.cpp | 11 +---------- src/p_lnspec.cpp | 8 ++++---- src/p_spec.h | 2 +- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index bda71d4a1..7b4fb2118 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -196,7 +196,6 @@ void DCeiling::Tick () { case ceilCrushAndRaise: case ceilLowerAndCrush: - case ceilLowerAndCrushDist: if (m_Speed1 == FRACUNIT && m_Speed2 == FRACUNIT) m_Speed = FRACUNIT / 8; break; @@ -259,16 +258,8 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, case ceilCrushRaiseAndStay: ceiling->m_TopHeight = sec->ceilingplane.d; case ceilLowerAndCrush: - case ceilLowerAndCrushDist: targheight = sec->FindHighestFloorPoint (&spot); - if (type == ceilLowerAndCrush) - { - targheight += 8*FRACUNIT; - } - else if (type == ceilCrushAndRaise) - { - targheight += height; - } + targheight += height; ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); ceiling->m_Direction = -1; break; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 857c8ef87..f892f35b6 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -652,19 +652,19 @@ FUNC(LS_Ceiling_RaiseByValueTimes8) FUNC(LS_Ceiling_CrushAndRaise) // Ceiling_CrushAndRaise (tag, speed, crush, crushtype) { - return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0, CRUSHTYPE(arg3)); + return EV_DoCeiling (DCeiling::ceilCrushAndRaise, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 8*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg3)); } FUNC(LS_Ceiling_LowerAndCrush) // Ceiling_LowerAndCrush (tag, speed, crush, crushtype) { - return EV_DoCeiling (DCeiling::ceilLowerAndCrush, ln, arg0, SPEED(arg1), SPEED(arg1), 0, arg2, 0, 0, CRUSHTYPE(arg3)); + return EV_DoCeiling (DCeiling::ceilLowerAndCrush, ln, arg0, SPEED(arg1), SPEED(arg1), 8*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg3)); } FUNC(LS_Ceiling_LowerAndCrushDist) // Ceiling_LowerAndCrush (tag, speed, crush, dist, crushtype) { - return EV_DoCeiling (DCeiling::ceilLowerAndCrushDist, ln, arg0, SPEED(arg1), SPEED(arg1), arg3*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg4)); + return EV_DoCeiling (DCeiling::ceilLowerAndCrush, ln, arg0, SPEED(arg1), SPEED(arg1), arg3*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg4)); } FUNC(LS_Ceiling_CrushStop) @@ -676,7 +676,7 @@ FUNC(LS_Ceiling_CrushStop) FUNC(LS_Ceiling_CrushRaiseAndStay) // Ceiling_CrushRaiseAndStay (tag, speed, crush, crushtype) { - return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 0, arg2, 0, 0, CRUSHTYPE(arg3)); + return EV_DoCeiling (DCeiling::ceilCrushRaiseAndStay, ln, arg0, SPEED(arg1), SPEED(arg1)/2, 8*FRACUNIT, arg2, 0, 0, CRUSHTYPE(arg3)); } FUNC(LS_Ceiling_MoveToValueTimes8) diff --git a/src/p_spec.h b/src/p_spec.h index f7bef6c42..e3b1c05ad 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -626,7 +626,7 @@ public: ceilRaiseInstant, ceilCrushAndRaise, ceilLowerAndCrush, - ceilLowerAndCrushDist, + ceil_placeholder, ceilCrushRaiseAndStay, ceilRaiseToNearest, ceilLowerToLowest, From f82c2170476edf121c14ef16f995ac9ee60b19b6 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Mon, 7 Mar 2016 10:53:51 -0600 Subject: [PATCH 17/27] Fixed: In multiplayer, players could spawn at voodoo doll starts - This could happen in co-op games that did not have enough player starts for all the players spawning. Voodoo doll starts were not excluded from the set of possible starts as they should have been. --- src/p_mobj.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index aa3691afa..cfbce5a73 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -5020,7 +5020,29 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // save spots for respawning in network games FPlayerStart start(mthing, pnum+1); playerstarts[pnum] = start; - AllPlayerStarts.Push(start); + if (level.flags2 & LEVEL2_RANDOMPLAYERSTARTS) + { // When using random player starts, all starts count + AllPlayerStarts.Push(start); + } + else + { // When not using random player starts, later single player + // starts should override earlier ones, since the earlier + // ones are for voodoo dolls and not likely to be ideal for + // spawning regular players. + unsigned i; + for (i = 0; i < AllPlayerStarts.Size(); ++i) + { + if (AllPlayerStarts[i].type == pnum+1) + { + AllPlayerStarts[i] = start; + break; + } + } + if (i == AllPlayerStarts.Size()) + { + AllPlayerStarts.Push(start); + } + } if (!deathmatch && !(level.flags2 & LEVEL2_RANDOMPLAYERSTARTS)) { return P_SpawnPlayer(&start, pnum, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); From 3c25b2c066e55f58e09c02c27bacf464c145ed10 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Mar 2016 21:58:34 +0100 Subject: [PATCH 18/27] - some redesign of P_CheckSight to handle portals. Portal stuff not tested yet. --- src/actionspecials.h | 2 +- src/actor.h | 2 +- src/doomdata.h | 4 +- src/p_local.h | 2 +- src/p_map.cpp | 1 - src/p_maputl.cpp | 2 +- src/p_mobj.cpp | 3 +- src/p_sight.cpp | 281 ++++++++++++++++++++++++++++++++++--------- src/portal.cpp | 22 +++- src/portal.h | 6 + src/r_defs.h | 8 +- 11 files changed, 268 insertions(+), 65 deletions(-) diff --git a/src/actionspecials.h b/src/actionspecials.h index 07a177bfa..6d9d2feb8 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -140,7 +140,7 @@ DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2) DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3) // portal specials -DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3) +DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 4) // GZDoom/Vavoom specials // Although ZDoom doesn't support them it's better to have them defined so that // WADs using them somewhere can at least be started without aborting due diff --git a/src/actor.h b/src/actor.h index 344f5c267..760b11c27 100644 --- a/src/actor.h +++ b/src/actor.h @@ -743,7 +743,7 @@ public: inline bool IsNoClip2() const; void CheckPortalTransition(bool islinked); - fixedvec3 GetPortalTransition(fixed_t byoffset); + fixedvec3 GetPortalTransition(fixed_t byoffset, sector_t **pSec = NULL); // What species am I? virtual FName GetSpecies(); diff --git a/src/doomdata.h b/src/doomdata.h index 469847eaa..4d8254757 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -121,7 +121,7 @@ struct maplinedef2_t // LineDef attributes. // -enum ELineFlags +enum ELineFlags : unsigned { ML_BLOCKING =0x00000001, // solid, is an obstacle ML_BLOCKMONSTERS =0x00000002, // blocks monsters only @@ -163,6 +163,8 @@ enum ELineFlags ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING + + ML_PORTALCONNECT = 0x80000000, // for internal use only: This line connects to a sector with a linked portal (used to speed up sight checks.) }; diff --git a/src/p_local.h b/src/p_local.h index 47911f5f1..abd759d2a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -275,7 +275,7 @@ void P_PlayerStartStomp (AActor *actor, bool mononly=false); // [RH] Stomp on t void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); bool P_BounceWall (AActor *mo); bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); -bool P_CheckSight (const AActor *t1, const AActor *t2, int flags=0); +bool P_CheckSight (AActor *t1, AActor *t2, int flags=0); enum ESightFlags { diff --git a/src/p_map.cpp b/src/p_map.cpp index e3ed9329f..e4830c68f 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5575,7 +5575,6 @@ void P_FindBelowIntersectors(AActor *actor) if (!(actor->flags & MF_SOLID)) return; - AActor *thing; FPortalGroupArray check; FMultiBlockThingsIterator it(check, actor); FMultiBlockThingsIterator::CheckResult cres; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index ffaa2b4e4..20fe996a5 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -162,7 +162,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, front = linedef->frontsector; back = linedef->backsector; - if (!(flags & FFCF_NOPORTALS)) + if (!(flags & FFCF_NOPORTALS) && (linedef->flags & ML_PORTALCONNECT)) { if (!linedef->frontsector->PortalBlocksMovement(sector_t::ceiling)) fc = FIXED_MAX; if (!linedef->backsector->PortalBlocksMovement(sector_t::ceiling)) bc = FIXED_MAX; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index cfbce5a73..a9e23c2a8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3285,7 +3285,7 @@ void AActor::SetRoll(angle_t r, bool interpolate) } -fixedvec3 AActor::GetPortalTransition(fixed_t byoffset) +fixedvec3 AActor::GetPortalTransition(fixed_t byoffset, sector_t **pSec) { bool moved = false; sector_t *sec = Sector; @@ -3316,6 +3316,7 @@ fixedvec3 AActor::GetPortalTransition(fixed_t byoffset) else break; } } + if (pSec) *pSec = sec; return pos; } diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 0b1afe430..39807e484 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -48,13 +48,48 @@ static int sightcounts[6]; static cycle_t SightCycles; static cycle_t MaxSightCycles; +enum +{ + SO_TOPFRONT = 1, + SO_TOPBACK = 2, + SO_BOTTOMFRONT = 4, + SO_BOTTOMBACK = 8, + +}; + +struct SightOpening +{ + fixed_t top; + fixed_t bottom; + int range; + int portalflags; + + void SwapSides() + { + portalflags = ((portalflags & (SO_TOPFRONT | SO_BOTTOMFRONT)) << 1) | ((portalflags & (SO_TOPBACK | SO_BOTTOMBACK)) >> 1); + } +}; + +struct SightTask +{ + fixed_t frac; + fixed_t topslope; + fixed_t bottomslope; + int direction; + int portalgroup; +}; + + static TArray intercepts (128); +static TArray portals(32); class SightCheck { - fixed_t sightzstart; // eye z of looker - const AActor * sightthing; - const AActor * seeingthing; + fixedvec3 sightstart; + fixedvec2 sightend; + fixed_t startfrac; + + AActor * seeingthing; fixed_t lastztop; // z at last line fixed_t lastzbottom; // z at last line sector_t * lastsector; // last sector being entered by trace @@ -63,28 +98,95 @@ class SightCheck divline_t trace; unsigned int myseethrough; + void P_SightOpening(SightOpening &open, const line_t *linedef, fixed_t x, fixed_t y); bool PTR_SightTraverse (intercept_t *in); bool P_SightCheckLine (line_t *ld); - bool P_SightBlockLinesIterator (int x, int y); + int P_SightBlockLinesIterator (int x, int y); bool P_SightTraverseIntercepts (); public: - bool P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); + bool P_SightPathTraverse (); - SightCheck(const AActor * t1, const AActor * t2, int flags) + void init(AActor * t1, AActor * t2, sector_t *startsector, SightTask *task, int flags) { - lastztop = lastzbottom = sightzstart = t1->Z() + t1->height - (t1->height>>2); - lastsector = t1->Sector; - sightthing=t1; + sightstart = t1->PosRelative(startsector); + sightend = t2->PosRelative(startsector); + sightstart.z += t1->height - (t1->height >> 2); + + startfrac = task->frac; + trace = { sightstart.x, sightstart.y, sightend.x - sightstart.x, sightend.y - sightstart.y }; + lastztop = lastzbottom = sightstart.z; + lastsector = startsector; seeingthing=t2; - bottomslope = t2->Z() - sightzstart; - topslope = bottomslope + t2->height; + topslope = task->topslope; + bottomslope = task->bottomslope; Flags = flags; + portaldir = task->direction; myseethrough = FF_SEETHROUGH; + + if (portaldir != sector_t::floor && !t1->Sector->PortalBlocksSight(sector_t::ceiling)) + { + portals.Push({ 0, topslope, bottomslope, sector_t::ceiling, t1->Sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup }); + } + if (portaldir != sector_t::ceiling && !t1->Sector->PortalBlocksSight(sector_t::floor)) + { + portals.Push({ 0, topslope, bottomslope, sector_t::floor, t1->Sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup }); + } } }; +//========================================================================== +// +// P_SightOpening +// +// Simplified version that removes everything not needed for a sight check +// +//========================================================================== + +void SightCheck::P_SightOpening(SightOpening &open, const line_t *linedef, fixed_t x, fixed_t y) +{ + open.portalflags = 0; + sector_t *front = linedef->frontsector; + sector_t *back = linedef->backsector; + + if (back == NULL) + { + // single sided line + if (linedef->flags & ML_PORTALCONNECT) + { + if (!front->PortalBlocksSight(sector_t::ceiling)) open.portalflags |= SO_TOPFRONT; + if (!front->PortalBlocksSight(sector_t::floor)) open.portalflags |= SO_BOTTOMFRONT; + } + + open.range = 0; + return; + } + + + fixed_t fc = 0, ff = 0, bc = 0, bf = 0; + + if (linedef->flags & ML_PORTALCONNECT) + { + if (!front->PortalBlocksSight(sector_t::ceiling)) fc = FIXED_MAX, open.portalflags |= SO_TOPFRONT; + if (!back->PortalBlocksSight(sector_t::ceiling)) bc = FIXED_MAX, open.portalflags |= SO_TOPBACK; + if (!front->PortalBlocksSight(sector_t::floor)) ff = FIXED_MIN, open.portalflags |= SO_BOTTOMFRONT; + if (!back->PortalBlocksSight(sector_t::floor)) bf = FIXED_MIN, open.portalflags |= SO_BOTTOMBACK; + } + + if (fc == 0) fc = front->ceilingplane.ZatPoint(x, y); + if (bc == 0) bc = back->ceilingplane.ZatPoint(x, y); + if (ff == 0) ff = front->floorplane.ZatPoint(x, y); + if (bf == 0) bf = back->floorplane.ZatPoint(x, y); + + open.bottom = MAX(ff, bf); + open.top = MIN(fc, bc); + + // we only want to know if there is an opening, not how large it is. + open.range = open.bottom >= open.top ? 0 : 1; +} + + /* ============== = @@ -93,14 +195,12 @@ public: ============== */ -/* -static bool PTR_SightTraverse (intercept_t *in) -*/ bool SightCheck::PTR_SightTraverse (intercept_t *in) { line_t *li; fixed_t slope; - FLineOpening open; + SightOpening open; + int frontflag = -1; li = in->d.line; @@ -114,30 +214,68 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) fixed_t trX=trace.x + FixedMul (trace.dx, in->frac); fixed_t trY=trace.y + FixedMul (trace.dy, in->frac); - P_LineOpening (open, NULL, li, trX, trY); + P_SightOpening (open, li, trX, trY); - if (open.range <= 0) // quick test for totally closed doors + FLinePortal *lport = li->getPortal(); + + if (open.range == 0 && open.portalflags == 0 && (lport == NULL || lport->mType != PORTT_LINKED)) // quick test for totally closed doors (must be delayed if portal checks are needed, though) return false; // stop // check bottom - slope = FixedDiv (open.bottom - sightzstart, in->frac); - if (slope > bottomslope) - bottomslope = slope; + if (open.bottom > FIXED_MIN) + { + slope = FixedDiv(open.bottom - sightstart.z, in->frac); + if (slope > bottomslope) + bottomslope = slope; + } // check top - slope = FixedDiv (open.top - sightzstart, in->frac); - if (slope < topslope) - topslope = slope; + if (open.top < FIXED_MAX) + { + slope = FixedDiv(open.top - sightstart.z, in->frac); + if (slope < topslope) + topslope = slope; + } - if (topslope <= bottomslope) + if (open.portalflags) + { + sector_t *frontsec, *backsec; + frontflag = P_PointOnLineSidePrecise(sightstart.x, sightstart.y, li); + if (!frontflag) + { + frontsec = li->frontsector; + backsec = li->backsector; + } + else + { + frontsec = li->backsector; + if (!frontsec) return false; // We are looking through the backside of a one-sided line. Just abort if that happens. + backsec = li->backsector; + open.SwapSides(); // swap flags to make the next checks simpler. + } + + if (portaldir != sector_t::floor && (open.portalflags & SO_TOPBACK) && !(open.portalflags & SO_TOPFRONT)) + { + portals.Push({ in->frac, topslope, bottomslope, sector_t::ceiling, backsec->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup }); + } + if (portaldir != sector_t::ceiling && (open.portalflags & SO_BOTTOMBACK) && !(open.portalflags & SO_BOTTOMFRONT)) + { + portals.Push({ in->frac, topslope, bottomslope, sector_t::floor, backsec->SkyBoxes[sector_t::floor]->Sector->PortalGroup }); + } + } + if (lport) + { + portals.Push({ in->frac, topslope, bottomslope, portaldir, lport->mDestination->frontsector->PortalGroup }); + return false; + } + + if (topslope <= bottomslope || open.range == 0) return false; // stop // now handle 3D-floors if(li->frontsector->e->XFloor.ffloors.Size() || li->backsector->e->XFloor.ffloors.Size()) { - int frontflag; - - frontflag = P_PointOnLineSidePrecise(sightthing->X(), sightthing->Y(), li); + if (frontflag == -1) frontflag = P_PointOnLineSidePrecise(sightstart.x, sightstart.y, li); //Check 3D FLOORS! for(int i=1;i<=2;i++) @@ -145,8 +283,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) sector_t * s=i==1? li->frontsector:li->backsector; fixed_t highslope, lowslope; - fixed_t topz= FixedMul (topslope, in->frac) + sightzstart; - fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightzstart; + fixed_t topz= FixedMul (topslope, in->frac) + sightstart.z; + fixed_t bottomz= FixedMul (bottomslope, in->frac) + sightstart.z; for(unsigned int j=0;je->XFloor.ffloors.Size();j++) { @@ -158,8 +296,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) fixed_t ff_bottom=rover->bottom.plane->ZatPoint(trX, trY); fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY); - highslope = FixedDiv (ff_top - sightzstart, in->frac); - lowslope = FixedDiv (ff_bottom - sightzstart, in->frac); + highslope = FixedDiv (ff_top - sightstart.z, in->frac); + lowslope = FixedDiv (ff_bottom - sightstart.z, in->frac); if (highslope>=topslope) { @@ -221,8 +359,8 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) } else lastsector=NULL; // don't need it if there are no 3D-floors - lastztop= FixedMul (topslope, in->frac) + sightzstart; - lastzbottom= FixedMul (bottomslope, in->frac) + sightzstart; + lastztop= FixedMul (topslope, in->frac) + sightstart.z; + lastzbottom= FixedMul (bottomslope, in->frac) + sightstart.z; return true; // keep going } @@ -308,18 +446,22 @@ bool SightCheck::P_SightCheckLine (line_t *ld) =================== */ -bool SightCheck::P_SightBlockLinesIterator (int x, int y) +int SightCheck::P_SightBlockLinesIterator (int x, int y) { int offset; int *list; + int res = 1; + bool portals; polyblock_t *polyLink; unsigned int i; extern polyblock_t **PolyBlockMap; offset = y*bmapwidth+x; + portals = PortalBlockmap(x, y).containsLinkedPortals; polyLink = PolyBlockMap[offset]; + portals |= (polyLink && PortalBlockmap.hasLinkedPolyPortals); while (polyLink) { if (polyLink->polyobj) @@ -329,8 +471,11 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y) polyLink->polyobj->validcount = validcount; for (i = 0; i < polyLink->polyobj->Linedefs.Size(); i++) { - if (!P_SightCheckLine (polyLink->polyobj->Linedefs[i])) - return false; + if (!P_SightCheckLine(polyLink->polyobj->Linedefs[i])) + { + if (!portals) return 0; + else res = -1; + } } } } @@ -342,10 +487,13 @@ bool SightCheck::P_SightBlockLinesIterator (int x, int y) for (list = blockmaplump + offset + 1; *list != -1; list++) { if (!P_SightCheckLine (&lines[*list])) - return false; + { + if (!portals) return 0; + else res = -1; + } } - return true; // everything was checked + return res; // everything was checked } /* @@ -378,8 +526,7 @@ bool SightCheck::P_SightTraverseIntercepts () // // go through in order -// [RH] Is it really necessary to go through in order? All we care about is if -// the trace is obstructed, not what specifically obstructed it. +// proper order is needed to handle 3D floors and portals. // in = NULL; @@ -408,8 +555,8 @@ bool SightCheck::P_SightTraverseIntercepts () { // we must do one last check whether the trace has crossed a 3D floor in the last sector - fixed_t topz= topslope + sightzstart; - fixed_t bottomz= bottomslope + sightzstart; + fixed_t topz= topslope + sightstart.z; + fixed_t bottomz= bottomslope + sightstart.z; for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) { @@ -441,8 +588,9 @@ bool SightCheck::P_SightTraverseIntercepts () ================== */ -bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) +bool SightCheck::P_SightPathTraverse () { + fixed_t x1, x2, y1, y2; fixed_t xt1,yt1,xt2,yt2; long long _x1,_y1,_x2,_y2; fixed_t xstep,ystep; @@ -453,6 +601,11 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ validcount++; intercepts.Clear (); + x1 = sightstart.x + FixedMul(startfrac, trace.dx); + y1 = sightstart.y + FixedMul(startfrac, trace.dy); + x2 = sightend.x; + y2 = sightend.y; + if (lastsector == NULL) lastsector = P_PointInSector(x1, y1); // for FF_SEETHROUGH the following rule applies: // If the viewer is in an area without FF_SEETHROUGH he can only see into areas without this flag @@ -463,10 +616,10 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ if(!(rover->flags & FF_EXISTS)) continue; - fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightthing); - fixed_t ff_top=rover->top.plane->ZatPoint(sightthing); + fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightstart); + fixed_t ff_top=rover->top.plane->ZatPoint(sightstart); - if (sightzstart < ff_top && sightzstart >= ff_bottom) + if (sightstart.z < ff_top && sightstart.z >= ff_bottom) { myseethrough = rover->flags & FF_SEETHROUGH; break; @@ -477,10 +630,6 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ x1 += FRACUNIT; // don't side exactly on a line if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0) y1 += FRACUNIT; // don't side exactly on a line - trace.x = x1; - trace.y = y1; - trace.dx = x2 - x1; - trace.dy = y2 - y1; _x1 = (long long)x1 - bmaporgx; _y1 = (long long)y1 - bmaporgy; @@ -572,13 +721,15 @@ bool SightCheck::P_SightPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_ for (count = 0 ; count < 100 ; count++) { - if (!P_SightBlockLinesIterator (mapx, mapy)) + int res = P_SightBlockLinesIterator(mapx, mapy); + if (res == 0) { sightcounts[1]++; return false; // early out } - if ((mapxstep | mapystep) == 0) + // either reached the end or had an early-out condition with portals left to check, + if (res == -1 || (mapxstep | mapystep) == 0) break; switch ((((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx)) @@ -649,7 +800,7 @@ sightcounts[2]++; ===================== */ -bool P_CheckSight (const AActor *t1, const AActor *t2, int flags) +bool P_CheckSight (AActor *t1, AActor *t2, int flags) { SightCycles.Clock(); @@ -717,8 +868,28 @@ sightcounts[0]++; validcount++; { - SightCheck s(t1, t2, flags); - res = s.P_SightPathTraverse (t1->X(), t1->Y(), t2->X(), t2->Y()); + sector_t *sec; + fixed_t lookheight = t1->height - (t1->height >> 2); + t1->GetPortalTransition(lookheight, &sec); + + fixed_t bottomslope = t2->Z() - (t1->Z() + lookheight); + fixed_t topslope = bottomslope + t2->height; + SightTask task = { 0, topslope, bottomslope, -1, sec->PortalGroup }; + + + SightCheck s; + s.init(t1, t2, sec, &task, flags); + res = s.P_SightPathTraverse (); + if (!res) + { + fixed_t dist = t1->AproxDistance(t2); + for (unsigned i = 0; i < portals.Size(); i++) + { + portals[i].frac += FixedDiv(FRACUNIT, dist); + s.init(t1, t2, NULL, &portals[i], flags); + if (s.P_SightPathTraverse()) break; + } + } } done: diff --git a/src/portal.cpp b/src/portal.cpp index e37697944..d615da3c9 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -122,15 +122,27 @@ static void BuildBlockmap() PortalBlockmap.containsLines = true; block.portallines.Push(ld); block.neighborContainsLines = true; + if (ld->getPortal()->mType == PORTT_LINKED) block.containsLinkedPortals = true; if (x > 0) PortalBlockmap(x - 1, y).neighborContainsLines = true; if (y > 0) PortalBlockmap(x, y - 1).neighborContainsLines = true; if (x < PortalBlockmap.dx - 1) PortalBlockmap(x + 1, y).neighborContainsLines = true; if (y < PortalBlockmap.dy - 1) PortalBlockmap(x, y + 1).neighborContainsLines = true; } + else + { + + bool yes = ld->frontsector->PortalIsLinked(sector_t::ceiling) || ld->frontsector->PortalIsLinked(sector_t::floor); + if (ld->backsector) + { + yes |= ld->backsector->PortalIsLinked(sector_t::ceiling) || ld->backsector->PortalIsLinked(sector_t::floor); + } + block.containsLinkedPortals |= yes; + PortalBlockmap.hasLinkedSectorPortals |= yes; + + } } } } - if (!PortalBlockmap.containsLines) PortalBlockmap.Clear(); } //=========================================================================== @@ -1066,6 +1078,14 @@ void P_CreateLinkedPortals() { sectors[i].CheckPortalPlane(sector_t::floor); sectors[i].CheckPortalPlane(sector_t::ceiling); + // set a flag on each line connecting to a plane portal sector. This is used to reduce the amount of checks in P_CheckSight. + if (sectors[i].PortalIsLinked(sector_t::floor) || sectors[i].PortalIsLinked(sector_t::ceiling)) + { + for (int j = 0; j < sectors[j].linecount; j++) + { + sectors[i].lines[j]->flags |= ML_PORTALCONNECT; + } + } } //BuildBlockmap(); } diff --git a/src/portal.h b/src/portal.h index b8a5d3ba3..d5a781f2d 100644 --- a/src/portal.h +++ b/src/portal.h @@ -78,11 +78,13 @@ extern FDisplacementTable Displacements; struct FPortalBlock { bool neighborContainsLines; // this is for skipping the traverser and exiting early if we can quickly decide that there's no portals nearby. + bool containsLinkedPortals; // this is for sight check optimization. We can't early-out on an impenetrable line if there may be portals being found in the same block later on. TArray portallines; FPortalBlock() { neighborContainsLines = false; + containsLinkedPortals = false; } }; @@ -91,6 +93,8 @@ struct FPortalBlockmap TArray data; int dx, dy; bool containsLines; + bool hasLinkedSectorPortals; // global flag to shortcut portal checks if the map has none. + bool hasLinkedPolyPortals; // this means that any early-outs in P_CheckSight need to be disabled if a block contains polyobjects. void Create(int blockx, int blocky) { @@ -105,6 +109,8 @@ struct FPortalBlockmap data.ShrinkToFit(); dx = dy = 0; containsLines = false; + hasLinkedPolyPortals = false; + hasLinkedSectorPortals = false; } FPortalBlock &operator()(int x, int y) diff --git a/src/r_defs.h b/src/r_defs.h index 468144ffc..248329da4 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -185,7 +185,6 @@ public: // class DSectorEffect; struct sector_t; -struct line_t; struct FRemapTable; enum @@ -769,7 +768,7 @@ struct sector_t bool PortalBlocksSight(int plane) { if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true; - return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); + return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } bool PortalBlocksMovement(int plane) @@ -784,6 +783,11 @@ struct sector_t return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED)); } + bool PortalIsLinked(int plane) + { + return (SkyBoxes[plane] != NULL && SkyBoxes[plane]->special1 == SKYBOX_LINKEDPORTAL); + } + // These may only be called if the portal has been validated fixedvec2 FloorDisplacement() { From cc2885c2ded8afc906b79a7feab2f89e864f804a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Mar 2016 22:05:19 +0100 Subject: [PATCH 19/27] - fixed int/fixed_t mixup with P_RadiusAttack's 'bombdistance' parameter. (Why is this thing even an int...?) --- src/p_map.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index e4830c68f..e3ab370d0 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5245,12 +5245,13 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo if (bombdistance <= 0) return; fulldamagedistance = clamp(fulldamagedistance, 0, bombdistance - 1); + fixed_t bombdistfix = bombdistance << FRACBITS; double bombdistancefloat = 1.f / (double)(bombdistance - fulldamagedistance); double bombdamagefloat = (double)bombdamage; FPortalGroupArray grouplist; - FMultiBlockThingsIterator it(grouplist, bombspot->X(), bombspot->Y(), bombspot->Z() - (bombdistance<height + ((bombdistance*2)<X(), bombspot->Y(), bombspot->Z() - bombdistfix, bombspot->height + bombdistfix*2, bombdistfix); FMultiBlockThingsIterator::CheckResult cres; if (flags & RADF_SOURCEISSPOT) From bd29f0994f1330d0133a9efcfb43c14f416582e5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 7 Mar 2016 23:41:16 +0100 Subject: [PATCH 20/27] - restored accidentally deleted line. --- src/p_sight.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 39807e484..e253b90a4 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -96,6 +96,7 @@ class SightCheck fixed_t topslope, bottomslope; // slopes to top and bottom of target int Flags; divline_t trace; + int portaldir; unsigned int myseethrough; void P_SightOpening(SightOpening &open, const line_t *linedef, fixed_t x, fixed_t y); From 2cd74118f656a6a4afba3c8d78150267ba62cdac Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 8 Mar 2016 01:26:13 +0100 Subject: [PATCH 21/27] - fixed sight checking through portals. Notes: * It is actually not enough to disable the early-out condition for the current block if there's a portal. It must be disabled for the entire rest of the trace because otherwise the collected lines never get processed. * The block bounds check cannot be done globally with portals in the game. The actual trace can easily end up outside the blockmap bounds if portal offsets are factored into the distance between the two actors. --- src/actor.h | 1 + src/p_sight.cpp | 46 ++++++++++++++++++++++++++++++---------------- src/r_defs.h | 5 +++++ 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/actor.h b/src/actor.h index 760b11c27..6ff2a6576 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1217,6 +1217,7 @@ public: return __pos; } + fixedvec3 PosRelative(int grp) const; fixedvec3 PosRelative(const AActor *other) const; fixedvec3 PosRelative(sector_t *sec) const; fixedvec3 PosRelative(line_t *line) const; diff --git a/src/p_sight.cpp b/src/p_sight.cpp index e253b90a4..b88be347b 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -97,6 +97,7 @@ class SightCheck int Flags; divline_t trace; int portaldir; + bool portalfound; unsigned int myseethrough; void P_SightOpening(SightOpening &open, const line_t *linedef, fixed_t x, fixed_t y); @@ -110,8 +111,8 @@ public: void init(AActor * t1, AActor * t2, sector_t *startsector, SightTask *task, int flags) { - sightstart = t1->PosRelative(startsector); - sightend = t2->PosRelative(startsector); + sightstart = t1->PosRelative(task->portalgroup); + sightend = t2->PosRelative(task->portalgroup); sightstart.z += t1->height - (t1->height >> 2); startfrac = task->frac; @@ -123,6 +124,7 @@ public: bottomslope = task->bottomslope; Flags = flags; portaldir = task->direction; + portalfound = false; myseethrough = FF_SEETHROUGH; @@ -251,7 +253,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) { frontsec = li->backsector; if (!frontsec) return false; // We are looking through the backside of a one-sided line. Just abort if that happens. - backsec = li->backsector; + backsec = li->frontsector; open.SwapSides(); // swap flags to make the next checks simpler. } @@ -452,17 +454,19 @@ int SightCheck::P_SightBlockLinesIterator (int x, int y) int offset; int *list; int res = 1; - bool portals; polyblock_t *polyLink; unsigned int i; extern polyblock_t **PolyBlockMap; offset = y*bmapwidth+x; - portals = PortalBlockmap(x, y).containsLinkedPortals; + + // if any of the previous blocks may contain a portal we may abort the collection of lines here, but we may not abort the sight check. + // (We still try to delay activating this for as long as possible.) + portalfound = portalfound || PortalBlockmap(x, y).containsLinkedPortals; polyLink = PolyBlockMap[offset]; - portals |= (polyLink && PortalBlockmap.hasLinkedPolyPortals); + portalfound |= (polyLink && PortalBlockmap.hasLinkedPolyPortals); while (polyLink) { if (polyLink->polyobj) @@ -474,7 +478,7 @@ int SightCheck::P_SightBlockLinesIterator (int x, int y) { if (!P_SightCheckLine(polyLink->polyobj->Linedefs[i])) { - if (!portals) return 0; + if (!portalfound) return 0; else res = -1; } } @@ -489,7 +493,7 @@ int SightCheck::P_SightBlockLinesIterator (int x, int y) { if (!P_SightCheckLine (&lines[*list])) { - if (!portals) return 0; + if (!portalfound) return 0; else res = -1; } } @@ -523,6 +527,11 @@ bool SightCheck::P_SightTraverseIntercepts () scan = &intercepts[scanpos]; P_MakeDivline (scan->d.line, &dl); scan->frac = P_InterceptVector (&trace, &dl); + if (scan->frac < startfrac) + { + scan->frac = FIXED_MAX; + count--; + } } // @@ -646,12 +655,6 @@ bool SightCheck::P_SightPathTraverse () xt2 = int(_x2 >> MAPBLOCKSHIFT); yt2 = int(_y2 >> MAPBLOCKSHIFT); -// points should never be out of bounds, but check once instead of -// each block - if (xt1<0 || yt1<0 || xt1>=bmapwidth || yt1>=bmapheight - || xt2<0 || yt2<0 || xt2>=bmapwidth || yt2>=bmapheight) - return false; - if (xt2 > xt1) { mapxstep = 1; @@ -722,10 +725,16 @@ bool SightCheck::P_SightPathTraverse () for (count = 0 ; count < 100 ; count++) { + // end traversing when reaching the end of the blockmap + // an early out is not possible because with portals a trace can easily land outside the map's bounds. + if (mapx < 0 || mapx >= bmapwidth || mapy < 0 || mapy >= bmapheight) + { + break; + } int res = P_SightBlockLinesIterator(mapx, mapy); if (res == 0) { -sightcounts[1]++; + sightcounts[1]++; return false; // early out } @@ -868,6 +877,7 @@ sightcounts[0]++; // Now look from eyes of t1 to any part of t2. validcount++; + portals.Clear(); { sector_t *sec; fixed_t lookheight = t1->height - (t1->height >> 2); @@ -888,7 +898,11 @@ sightcounts[0]++; { portals[i].frac += FixedDiv(FRACUNIT, dist); s.init(t1, t2, NULL, &portals[i], flags); - if (s.P_SightPathTraverse()) break; + if (s.P_SightPathTraverse()) + { + res = true; + break; + } } } } diff --git a/src/r_defs.h b/src/r_defs.h index 248329da4..3e6574e56 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1267,6 +1267,11 @@ inline sector_t *P_PointInSector(fixed_t x, fixed_t y) return P_PointInSubsector(x, y)->sector; } +inline fixedvec3 AActor::PosRelative(int portalgroup) const +{ + return __pos + Displacements.getOffset(Sector->PortalGroup, portalgroup); +} + inline fixedvec3 AActor::PosRelative(const AActor *other) const { return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup); From 50d2145ba041c55d4f81e1b3b72545948db5be83 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 8 Mar 2016 09:41:54 +0100 Subject: [PATCH 22/27] - fixed typo in portal init code. --- src/portal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portal.cpp b/src/portal.cpp index d615da3c9..6ec1c6c1d 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -1081,7 +1081,7 @@ void P_CreateLinkedPortals() // set a flag on each line connecting to a plane portal sector. This is used to reduce the amount of checks in P_CheckSight. if (sectors[i].PortalIsLinked(sector_t::floor) || sectors[i].PortalIsLinked(sector_t::ceiling)) { - for (int j = 0; j < sectors[j].linecount; j++) + for (int j = 0; j < sectors[i].linecount; j++) { sectors[i].lines[j]->flags |= ML_PORTALCONNECT; } From f35d96679979f49dda73aa6eeda84f801ecfb8ae Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 8 Mar 2016 10:09:02 +0100 Subject: [PATCH 23/27] - don't allow any ceiling portal that has a lower position than a floor portal in the same sector. The will inevitably lead to problematic situations. --- src/portal.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/portal.cpp b/src/portal.cpp index 6ec1c6c1d..a6446a82b 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -1086,6 +1086,26 @@ void P_CreateLinkedPortals() sectors[i].lines[j]->flags |= ML_PORTALCONNECT; } } + if (sectors[i].PortalIsLinked(sector_t::ceiling) && sectors[i].PortalIsLinked(sector_t::floor)) + { + fixed_t cz = sectors[i].SkyBoxes[sector_t::ceiling]->threshold; + fixed_t fz = sectors[i].SkyBoxes[sector_t::floor]->threshold; + if (cz < fz) + { + // This is a fatal condition. We have to remove one of the two portals. Choose the one that doesn't match the current plane + Printf("Error in sector %d: Ceiling portal at z=%d is below floor portal at z=%d\n", i, cz, fz); + fixed_t cp = sectors[i].ceilingplane.Zat0(); + fixed_t fp = sectors[i].ceilingplane.Zat0(); + if (cp < fp || fz == fp) + { + sectors[i].SkyBoxes[sector_t::ceiling] = NULL; + } + else + { + sectors[i].SkyBoxes[sector_t::floor] = NULL; + } + } + } } //BuildBlockmap(); } From f852ead99a4a04c1c6cde3a2e385e40ce752abdd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 8 Mar 2016 10:44:03 +0100 Subject: [PATCH 24/27] - fixed: The initial check for ceiling and floor portals must be done when the trace's start position and its sector has been calculated. SightCheck::init is too early for that. --- src/p_sight.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/p_sight.cpp b/src/p_sight.cpp index b88be347b..7669ac888 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -97,6 +97,7 @@ class SightCheck int Flags; divline_t trace; int portaldir; + int portalgroup; bool portalfound; unsigned int myseethrough; @@ -127,15 +128,6 @@ public: portalfound = false; myseethrough = FF_SEETHROUGH; - - if (portaldir != sector_t::floor && !t1->Sector->PortalBlocksSight(sector_t::ceiling)) - { - portals.Push({ 0, topslope, bottomslope, sector_t::ceiling, t1->Sector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup }); - } - if (portaldir != sector_t::ceiling && !t1->Sector->PortalBlocksSight(sector_t::floor)) - { - portals.Push({ 0, topslope, bottomslope, sector_t::floor, t1->Sector->SkyBoxes[sector_t::floor]->Sector->PortalGroup }); - } } }; @@ -620,6 +612,7 @@ bool SightCheck::P_SightPathTraverse () // for FF_SEETHROUGH the following rule applies: // If the viewer is in an area without FF_SEETHROUGH he can only see into areas without this flag // If the viewer is in an area with FF_SEETHROUGH he can only see into areas with this flag + bool checkfloor = true, checkceiling = true; for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) { F3DFloor* rover = lastsector->e->XFloor.ffloors[i]; @@ -629,6 +622,9 @@ bool SightCheck::P_SightPathTraverse () fixed_t ff_bottom=rover->bottom.plane->ZatPoint(sightstart); fixed_t ff_top=rover->top.plane->ZatPoint(sightstart); + if (sightstart.z < ff_top) checkceiling = false; + if (sightstart.z >= ff_bottom) checkfloor = false; + if (sightstart.z < ff_top && sightstart.z >= ff_bottom) { myseethrough = rover->flags & FF_SEETHROUGH; @@ -636,6 +632,16 @@ bool SightCheck::P_SightPathTraverse () } } + // We also must check if the starting sector contains portals, and start sight checks in those as well. + if (portaldir != sector_t::floor && checkceiling && !lastsector->PortalBlocksSight(sector_t::ceiling)) + { + portals.Push({ 0, topslope, bottomslope, sector_t::ceiling, lastsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup }); + } + if (portaldir != sector_t::ceiling && checkfloor && !lastsector->PortalBlocksSight(sector_t::floor)) + { + portals.Push({ 0, topslope, bottomslope, sector_t::floor, lastsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup }); + } + if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) x1 += FRACUNIT; // don't side exactly on a line if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0) From 4ebdcb7b6de4ca46eac3e9f6860e5f9094299974 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 8 Mar 2016 11:55:40 +0100 Subject: [PATCH 25/27] - fixed: The result condition of a hitscan subtrace was never checked. --- src/p_trace.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 2e96db7c9..2dec3d9d5 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -842,7 +842,9 @@ bool FTraceInfo::TraceTraverse (int ptflags) } else if (in->isaline) { - if (!LineCheck(in)) break; + bool res = LineCheck(in); + if (aimdir == INT_MAX) return res; // signal for immediate abort + if (!res) break; } else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis) { From e11a0986cea3e04ed9ec4ab4f437d612246b6dfd Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 8 Mar 2016 12:27:01 +0100 Subject: [PATCH 26/27] - encountered a strange crash that after changing a map, InSubsector was not NULL and pointing to invalid data. So let's better NULL this variable explicitly each time a render loop is started. --- src/r_bsp.cpp | 2 +- src/r_main.cpp | 5 ++++- src/r_plane.cpp | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index 44a97eb36..97ac7e5e3 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -101,7 +101,7 @@ WORD MirrorFlags; TArray WallPortals(1000); // note: this array needs to go away as reallocation can cause crashes. -static subsector_t *InSubsector; +subsector_t *InSubsector; CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs? diff --git a/src/r_main.cpp b/src/r_main.cpp index 43c22b0f9..44ed781bb 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -86,6 +86,8 @@ static void R_ShutdownRenderer(); extern short *openings; extern bool r_fakingunderwater; extern "C" int fuzzviewheight; +extern subsector_t *InSubsector; +extern bool r_showviewer; // PRIVATE DATA DECLARATIONS ----------------------------------------------- @@ -93,7 +95,6 @@ extern "C" int fuzzviewheight; static float CurrentVisibility = 8.f; static fixed_t MaxVisForWall; static fixed_t MaxVisForFloor; -extern bool r_showviewer; bool r_dontmaplines; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -772,6 +773,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) memcpy (ceilingclip + pds->x1, &pds->ceilingclip[0], pds->len*sizeof(*ceilingclip)); memcpy (floorclip + pds->x1, &pds->floorclip[0], pds->len*sizeof(*floorclip)); + InSubsector = NULL; R_RenderBSPNode (nodes + numnodes - 1); R_3D_ResetClip(); // reset clips (floor/ceiling) @@ -916,6 +918,7 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) } // Link the polyobjects right before drawing the scene to reduce the amounts of calls to this function PO_LinkToSubsectors(); + InSubsector = NULL; R_RenderBSPNode (nodes + numnodes - 1); // The head node is the last node output. R_3D_ResetClip(); // reset clips (floor/ceiling) camera->renderflags = savedflags; diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 4f906b1b6..15653a1e8 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -66,6 +66,8 @@ //EXTERN_CVAR (Int, tx) //EXTERN_CVAR (Int, ty) +extern subsector_t *InSubsector; + static void R_DrawSkyStriped (visplane_t *pl); planefunction_t floorfunc; @@ -1314,6 +1316,7 @@ void R_DrawSkyBoxes () viewzStack.Push (viewz); visplaneStack.Push (pl); + InSubsector = NULL; R_RenderBSPNode (nodes + numnodes - 1); R_3D_ResetClip(); // reset clips (floor/ceiling) R_DrawPlanes (); From 1815b076eec3e960df0deae575adb1d2c9ac0074 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 8 Mar 2016 13:07:21 +0100 Subject: [PATCH 27/27] - don't show the IWAD picker upon restart. This doesn't work with fullscreen mode. Instead just pick the first IWAD from the list until a better solution can be implemented. - handle a 'restart' CCMD a bit more controlled. Instead of throwing an exception in the CCMD handler it now just flags D_DoomLoop to return. If the exception is thrown within the CCMD this can easily happen deep inside the renderer when it calls NetUpdate. But since the software renderer with its use of global variables is not equipped to be yanked out of lile this it could leave broken data behind that caused glitches or even crashes on subsequently played maps. --- src/d_main.cpp | 108 +++++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 9c0007bc3..accb6c247 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -205,6 +205,7 @@ CUSTOM_CVAR (String, vid_cursor, "None", CVAR_ARCHIVE | CVAR_NOINITCALL) } } +bool wantToRestart; bool DrawFSHUD; // [RH] Draw fullscreen HUD? TArray allwads; bool devparm; // started game with -devparm @@ -1012,6 +1013,11 @@ void D_DoomLoop () I_StartTic (); D_Display (); S_UpdateMusic(); // OpenAL needs this to keep the music running, thanks to a complete lack of a sane streaming implementation using callbacks. :( + if (wantToRestart) + { + wantToRestart = false; + return; + } } catch (CRecoverableError &error) { @@ -2635,59 +2641,58 @@ void D_DoomMain (void) setmodeneeded = false; // This may be set to true here, but isn't needed for a restart } - try + D_DoomLoop (); // this only returns if a 'restart' CCMD is given. + + // + // Clean up after a restart + // + + // Music and sound should be stopped first + S_StopMusic(true); + S_StopAllChannels (); + + M_ClearMenus(); // close menu if open + F_EndFinale(); // If an intermission is active, end it now + + // clean up game state + ST_Clear(); + D_ErrorCleanup (); + P_FreeLevelData(); + P_FreeExtraLevelData(); + + M_SaveDefaults(NULL); // save config before the restart + + // delete all data that cannot be left until reinitialization + V_ClearFonts(); // must clear global font pointers + R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. + gameinfo.~gameinfo_t(); + new (&gameinfo) gameinfo_t; // Reset gameinfo + S_Shutdown(); // free all channels and delete playlist + C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here + DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods + + GC::FullGC(); // clean up before taking down the object list. + + // Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions. + FAutoSegIterator probe(ARegHead, ARegTail); + while (*++probe != NULL) { - D_DoomLoop (); // never returns + AFuncDesc *afunc = (AFuncDesc *)*probe; + *(afunc->VMPointer) = NULL; } - catch (CRestartException &) + + ReleaseGlobalSymbols(); + PClass::StaticShutdown(); + + GC::FullGC(); // perform one final garbage collection after shutdown + + for (DObject *obj = GC::Root; obj; obj = obj->ObjNext) { - // Music and sound should be stopped first - S_StopMusic(true); - S_StopAllChannels (); - - M_ClearMenus(); // close menu if open - F_EndFinale(); // If an intermission is active, end it now - - // clean up game state - ST_Clear(); - D_ErrorCleanup (); - P_FreeLevelData(); - P_FreeExtraLevelData(); - - M_SaveDefaults(NULL); // save config before the restart - - // delete all data that cannot be left until reinitialization - V_ClearFonts(); // must clear global font pointers - R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. - gameinfo.~gameinfo_t(); - new (&gameinfo) gameinfo_t; // Reset gameinfo - S_Shutdown(); // free all channels and delete playlist - C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here - DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods - - GC::FullGC(); // clean up before taking down the object list. - - // Delete the VM functions here. The garbage collector will not do this automatically because they are referenced from the global action function definitions. - FAutoSegIterator probe(ARegHead, ARegTail); - while (*++probe != NULL) - { - AFuncDesc *afunc = (AFuncDesc *)*probe; - *(afunc->VMPointer) = NULL; - } - - ReleaseGlobalSymbols(); - PClass::StaticShutdown(); - - GC::FullGC(); // perform one final garbage collection after shutdown - - for (DObject *obj = GC::Root; obj; obj = obj->ObjNext) - { - obj->ClearClass(); // Delete the Class pointer because the data it points to has been deleted. This will automatically be reset if needed. - } - - restart++; - PClass::bShutdown = false; + obj->ClearClass(); // Delete the Class pointer because the data it points to has been deleted. This will automatically be reset if needed. } + + restart++; + PClass::bShutdown = false; } while (1); } @@ -2715,14 +2720,13 @@ CCMD(restart) if (argv.argc() > 1) { - for(int i=1;iAppendArg(argv[i]); } } - // initiate the restart - throw CRestartException(); + wantToRestart = true; } //==========================================================================