diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 397d2be1e7..08050133a8 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -776,6 +776,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li int highestfloorterrain = -1; FTextureID lowestceilingpic; sector_t *lowestceilingsec = NULL, *highestfloorsec = NULL; + secplane_t *highestfloorplanes[2] = { NULL, NULL }; highestfloorpic.SetInvalid(); lowestceilingpic.SetInvalid(); @@ -808,6 +809,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li highestfloorpic = *rover->top.texture; highestfloorterrain = rover->model->GetTerrain(rover->top.isceiling); highestfloorsec = j == 0 ? linedef->frontsector : linedef->backsector; + highestfloorplanes[j] = rover->top.plane; } if(ff_top > lowestfloor[j] && ff_top <= thing->Z() + thing->MaxStepHeight) lowestfloor[j] = ff_top; } @@ -826,6 +828,16 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li open.top = lowestceiling; open.ceilingpic = lowestceilingpic; open.topsec = lowestceilingsec; + if (highestfloorplanes[0]) + { + open.frontfloorplane = *highestfloorplanes[0]; + if (open.frontfloorplane.c < 0) open.frontfloorplane.FlipVert(); + } + if (highestfloorplanes[1]) + { + open.backfloorplane = *highestfloorplanes[1]; + if (open.backfloorplane.c < 0) open.backfloorplane.FlipVert(); + } } open.lowfloor = MIN(lowestfloor[0], lowestfloor[1]); diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp index 1c4ba7b7ca..c5a205891b 100644 --- a/src/p_3dmidtex.cpp +++ b/src/p_3dmidtex.cpp @@ -294,7 +294,9 @@ bool P_LineOpening_3dMidtex(AActor *thing, const line_t *linedef, FLineOpening & open.abovemidtex = true; open.floorpic = linedef->sidedef[0]->GetTexture(side_t::mid); open.floorterrain = TerrainTypes[open.floorpic]; - + open.frontfloorplane.SetAtHeight(tt, sector_t::floor); + open.backfloorplane.SetAtHeight(tt, sector_t::floor); + } // returns true if it touches the midtexture return (abs(thing->Z() - tt) <= thing->MaxStepHeight); diff --git a/src/p_map.cpp b/src/p_map.cpp index a7346fa17d..287ba0eeed 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -276,7 +276,7 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLines void P_GetFloorCeilingZ(FCheckPosition &tmf, int flags) { - sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.thing->Sector; + sector_t *sec = (!(flags & FFCF_SAMESECTOR) || tmf.thing->Sector == NULL)? P_PointInSector(tmf.x, tmf.y) : tmf.sector; F3DFloor *ffc, *fff; tmf.ceilingz = sec->NextHighestCeilingAt(tmf.thing, tmf.z + tmf.thing->height, flags, &tmf.ceilingsector, &ffc); @@ -316,6 +316,10 @@ void P_FindFloorCeiling(AActor *actor, int flags) { flags |= FFCF_3DRESTRICT; } + if (flags & FFCF_SAMESECTOR) + { + tmf.sector = actor->Sector; + } P_GetFloorCeilingZ(tmf, flags); assert(tmf.thing->Sector != NULL); @@ -759,8 +763,9 @@ int P_GetMoveFactor(const AActor *mo, int *frictionp) //========================================================================== static // killough 3/26/98: make static -bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) +bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm) { + line_t *ld = cres.line; bool rail = false; if (box.Right() <= ld->bbox[BOXLEFT] @@ -802,7 +807,6 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) bool NotBlocked = ((tm.thing->flags3 & MF3_NOBLOCKMONST) || ((i_compatflags & COMPATF_NOBLOCKFRIENDS) && (tm.thing->flags & MF_FRIENDLY))); - fixedvec3 pos = tm.thing->PosRelative(ld); if (!(Projectile) || (ld->flags & (ML_BLOCKEVERYTHING | ML_BLOCKPROJECTILE))) { if (ld->flags & ML_RAILING) @@ -821,55 +825,33 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) } tm.thing->BlockingLine = ld; // Calculate line side based on the actor's original position, not the new one. - CheckForPushSpecial(ld, P_PointOnLineSide(pos.x, pos.y, ld), tm.thing, false); + CheckForPushSpecial(ld, P_PointOnLineSide(cres.position.x, cres.position.y, ld), tm.thing, false); return false; } } - // [RH] Steep sectors count as dropoffs (unless already in one) + fixedvec2 ref = FindRefPoint(ld, cres.position); + FLineOpening open; + + P_LineOpening(open, tm.thing, ld, ref.x, ref.y, cres.position.x, cres.position.y, cres.portalflags); + + // [RH] Steep sectors count as dropoffs, if the actor touches the boundary between a steep slope and something else if (!(tm.thing->flags & MF_DROPOFF) && !(tm.thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) { - secplane_t frontplane, backplane; // Check 3D floors as well - frontplane = P_FindFloorPlane(ld->frontsector, pos.x, pos.y, tm.thing->floorz); - backplane = P_FindFloorPlane(ld->backsector, pos.x, pos.y, tm.thing->floorz); - if (frontplane.c < STEEPSLOPE || backplane.c < STEEPSLOPE) + if ((open.frontfloorplane.c < STEEPSLOPE) != (open.backfloorplane.c < STEEPSLOPE)) { - const msecnode_t *node = tm.thing->touching_sectorlist; - bool allow = false; - int count = 0; - while (node != NULL) - { - count++; - if (node->m_sector->floorplane.c < STEEPSLOPE) - { - allow = true; - break; - } - node = node->m_tnext; - } - if (!allow) - { - return false; - } + // on the boundary of a steep slope + return false; } } - fixedvec2 rpos = { tm.x, tm.y }; - fixedvec2 ref = FindRefPoint(ld, rpos); - FLineOpening open; - - P_LineOpening(open, tm.thing, ld, ref.x, ref.y, tm.x, tm.y, 0); - - // the floorplane on both sides is identical with the current one - // so don't mess around with the z-position. - if (ld->frontsector->floorplane == ld->backsector->floorplane && - ld->frontsector->floorplane == tm.thing->Sector->floorplane && - !ld->frontsector->e->XFloor.ffloors.Size() && !ld->backsector->e->XFloor.ffloors.Size() && - !open.abovemidtex) + // If the floor planes on both sides we should recalculate open.bottom at the actual position we are checking + // This is to avoid bumpy movement when crossing a linedef with the same slope on both sides. + if (open.frontfloorplane == open.backfloorplane) { - open.bottom = INT_MIN; + open.bottom = open.frontfloorplane.ZatPoint(cres.position.x, cres.position.y); } if (rail && @@ -1017,8 +999,9 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter) // //========================================================================== -bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) +bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::CheckResult &cres, const FBoundingBox &box, FCheckPosition &tm) { + AActor *thing = cres.thing; fixed_t topz; bool solid; int damage; @@ -1440,56 +1423,29 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo tm.x = x; tm.y = y; + tm.z = thing->Z(); - newsec = P_PointInSector(x, y); + newsec = tm.sector = P_PointInSector(x, y); tm.ceilingline = thing->BlockingLine = NULL; - // The base floor / ceiling is from the subsector that contains the point. + // Retrieve the base floor / ceiling from the target location. // Any contacted lines the step closer together will adjust them. - tm.floorz = tm.dropoffz = newsec->LowestFloorAt(x, y, &tm.floorsector); - tm.ceilingz = newsec->HighestCeilingAt(x, y, &tm.ceilingsector); - tm.floorpic = tm.floorsector->GetTexture(sector_t::floor); - tm.floorterrain = tm.floorsector->GetTerrain(sector_t::floor); - tm.ceilingpic = tm.ceilingsector->GetTexture(sector_t::ceiling); - tm.touchmidtex = false; - tm.abovemidtex = false; - - //Added by MC: Fill the tmsector. - tm.sector = newsec; - - //Check 3D floors - if (!thing->IsNoClip2() && newsec->e->XFloor.ffloors.Size()) + if (!thing->IsNoClip2()) { - F3DFloor* rover; - fixed_t delta1; - fixed_t delta2; - int thingtop = thing->Z() + (thing->height == 0 ? 1 : thing->height); - - for (unsigned i = 0; ie->XFloor.ffloors.Size(); i++) - { - rover = newsec->e->XFloor.ffloors[i]; - if (!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; - - fixed_t ff_bottom = rover->bottom.plane->ZatPoint(x, y); - fixed_t ff_top = rover->top.plane->ZatPoint(x, y); - - delta1 = thing->Z() - (ff_bottom + ((ff_top - ff_bottom) / 2)); - delta2 = thingtop - (ff_bottom + ((ff_top - ff_bottom) / 2)); - - if (ff_top > tm.floorz && abs(delta1) < abs(delta2)) - { - tm.floorz = tm.dropoffz = ff_top; - tm.floorpic = *rover->top.texture; - tm.floorterrain = rover->model->GetTerrain(rover->top.isceiling); - } - if (ff_bottom < tm.ceilingz && abs(delta1) >= abs(delta2)) - { - tm.ceilingz = ff_bottom; - tm.ceilingpic = *rover->bottom.texture; - } - } + P_GetFloorCeilingZ(tm, FFCF_SAMESECTOR); + } + else + { + // With noclip2, we must ignore 3D floors and go right to the uppermost ceiling and lowermost floor. + tm.floorz = tm.dropoffz = newsec->LowestFloorAt(x, y, &tm.floorsector); + tm.ceilingz = newsec->HighestCeilingAt(x, y, &tm.ceilingsector); + tm.floorpic = tm.floorsector->GetTexture(sector_t::floor); + tm.floorterrain = tm.floorsector->GetTerrain(sector_t::floor); + tm.ceilingpic = tm.ceilingsector->GetTexture(sector_t::ceiling); } + tm.touchmidtex = false; + tm.abovemidtex = false; validcount++; spechit.Clear(); @@ -1507,51 +1463,52 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo tm.stepthing = NULL; FBoundingBox box(x, y, thing->radius); - { - FBlockThingsIterator it2(box); - AActor *th; - while ((th = it2.Next())) - { - if (!PIT_CheckThing(th, tm)) - { // [RH] If a thing can be stepped up on, we need to continue checking - // other things in the blocks and see if we hit something that is - // definitely blocking. Otherwise, we need to check the lines, or we - // could end up stuck inside a wall. - AActor *BlockingMobj = thing->BlockingMobj; + FPortalGroupArray pcheck; + FMultiBlockThingsIterator it2(pcheck, x, y, thing->Z(), thing->height, thing->radius); + FMultiBlockThingsIterator::CheckResult tcres; - if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ)) - { // Thing slammed into something; don't let it move now. - thing->height = realheight; - return false; - } - else if (!BlockingMobj->player && !(thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY)) && - BlockingMobj->Top() - thing->Z() <= thing->MaxStepHeight) - { - if (thingblocker == NULL || - BlockingMobj->Z() > thingblocker->Z()) - { - thingblocker = BlockingMobj; - } - thing->BlockingMobj = NULL; - } - else if (thing->player && - thing->Top() - BlockingMobj->Z() <= thing->MaxStepHeight) - { - if (thingblocker) - { // There is something to step up on. Return this thing as - // the blocker so that we don't step up. - thing->height = realheight; - return false; - } - // Nothing is blocking us, but this actor potentially could - // if there is something else to step on. - thing->BlockingMobj = NULL; - } - else - { // Definitely blocking + while ((it2.Next(&tcres))) + { + if (!PIT_CheckThing(it2, tcres, it2.Box(), tm)) + { // [RH] If a thing can be stepped up on, we need to continue checking + // other things in the blocks and see if we hit something that is + // definitely blocking. Otherwise, we need to check the lines, or we + // could end up stuck inside a wall. + AActor *BlockingMobj = thing->BlockingMobj; + + // If this blocks through a line portal with a vertical displacement, it will always completely block. There is no way to step up onto such an actor. + if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ) || tcres.zdiff != 0) + { // Thing slammed into something; don't let it move now. + thing->height = realheight; + return false; + } + else if (!BlockingMobj->player && !(thing->flags & (MF_FLOAT | MF_MISSILE | MF_SKULLFLY)) && + BlockingMobj->Top() - thing->Z() <= thing->MaxStepHeight) + { + if (thingblocker == NULL || + BlockingMobj->Z() > thingblocker->Z()) + { + thingblocker = BlockingMobj; + } + thing->BlockingMobj = NULL; + } + else if (thing->player && + thing->Top() - BlockingMobj->Z() <= thing->MaxStepHeight) + { + if (thingblocker) + { // There is something to step up on. Return this thing as + // the blocker so that we don't step up. thing->height = realheight; return false; } + // Nothing is blocking us, but this actor potentially could + // if there is something else to step on. + thing->BlockingMobj = NULL; + } + else + { // Definitely blocking + thing->height = realheight; + return false; } } } @@ -1574,7 +1531,8 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo if (actorsonly || (thing->flags & MF_NOCLIP)) return (thing->BlockingMobj = thingblocker) == NULL; - FBlockLinesIterator it(box); + FMultiBlockLinesIterator it(pcheck, thing); + FMultiBlockLinesIterator::CheckResult lcres; line_t *ld; fixed_t thingdropoffz = tm.floorz; @@ -1583,9 +1541,9 @@ bool P_CheckPosition(AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bo bool good = true; - while ((ld = it.Next())) + while (it.Next(&lcres)) { - good &= PIT_CheckLine(ld, box, tm); + good &= PIT_CheckLine(it, lcres, it.Box(), tm); } if (!good) { diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index 722d1a6ddd..0e82bf1120 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -229,6 +229,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.floorterrain = back->GetTerrain(sector_t::floor); open.lowfloor = ff; } + open.frontfloorplane = front->floorplane; + open.backfloorplane = back->floorplane; } else { // Dummy stuff to have some sort of opening for the 3D checks to modify @@ -240,6 +242,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef, open.floorterrain = -1; open.bottom = FIXED_MIN; open.lowfloor = FIXED_MAX; + open.frontfloorplane.SetAtHeight(FIXED_MIN, sector_t::floor); + open.backfloorplane.SetAtHeight(FIXED_MIN, sector_t::floor); } // Check 3D floors @@ -798,6 +802,7 @@ bool FMultiBlockLinesIterator::Next(FMultiBlockLinesIterator::CheckResult *item) item->position.x = offset.x; item->position.y = offset.y; item->position.z = checkpoint.z; + item->zdiff = 0; item->portalflags = portalflags; return true; } @@ -1085,6 +1090,7 @@ bool FMultiBlockThingsIterator::Next(FMultiBlockThingsIterator::CheckResult *ite { item->thing = thing; item->position = checkpoint + Displacements(basegroup, thing->Sector->PortalGroup); + item->zdiff = 0; item->portalflags = portalflags; return true; } diff --git a/src/p_maputl.h b/src/p_maputl.h index 11260bcbfe..3027df3d49 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -99,6 +99,8 @@ struct FLineOpening sector_t *topsec; FTextureID ceilingpic; FTextureID floorpic; + secplane_t frontfloorplane; + secplane_t backfloorplane; int floorterrain; bool touchmidtex; bool abovemidtex; @@ -221,6 +223,7 @@ public: { line_t *line; fixedvec3 position; + fixed_t zdiff; int portalflags; }; @@ -306,6 +309,7 @@ public: { AActor *thing; fixedvec3 position; + fixed_t zdiff; int portalflags; }; diff --git a/src/r_defs.h b/src/r_defs.h index c4444e9f11..ab55201f91 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -345,6 +345,21 @@ struct secplane_t return -TMulScale16 (a, v->x, b, v->y, z, c); } + void SetAtHeight(fixed_t height, int ceiling) + { + a = b = 0; + if (ceiling) + { + c = ic = -FRACUNIT; + d = height; + } + else + { + c = ic = FRACUNIT; + d = -height; + } + } + bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const; };